我真正想知道的是哪些反射方法会触发类型初始化?这对我来说有点不清楚。具体来说,如果应用于静态字段,那么所提到的两种方法GetField和GetValue是否会触发类型初始化?我已经尝试研究了这个问题,据我所知,执行诸如引用或访问静态字段等操作将触发所有静态字段的类型初始化。下面我引用了我认为相关的规范部分,但使用"引用"和"访问"等措辞恰恰是我的犹豫所在:
到底哪些操作才算是"访问"?
获取字段的FieldInfo元数据是否算作"引用"或"访问"该字段?
- 创建该类的实例。 - 引用了该类的任何静态成员。
如果一个类包含Main方法(§10.1),其中执行开始,则该类的静态构造函数在调用Main方法之前执行。如果一个类包含任何具有初始值设定项的静态字段,则这些初始化器将在执行静态构造函数之前按文本顺序立即执行(§17.4.5)。
更相关的是ECMA-335(CLI规范),类类型定义,第I部分,第8.9.5节。
到底哪些操作才算是"访问"?
获取字段的FieldInfo元数据是否算作"引用"或"访问"该字段?
请帮助我找到规范的相关部分,以便我知道我的代码*是安全的、符合规范的,而不仅仅是因为某些未记录的实现细节或行星恰好排列正确而"碰巧工作"。
我的代码通过了测试,但依赖于类型初始化行为。我在这里没有展示我的代码,因为它很冗长,问题也不是想要一个“你的代码看起来不错”的回复,而是我想学习如何以及为什么这样做,以便自己评估我的代码是否符合规范,并且(假设符合规范)思考我可以对其进行哪些更改而无需每次都问一个新问题。请注意保留HTML标签。到目前为止,我了解以下规范的内容,其中使用了上述术语“引用”和“访问”:
我知道ECMA-334(C#语言规范),静态字段初始化,第17.4.5.1节
如果类中存在静态构造函数(§17.11),则在执行该静态构造函数之前立即执行静态字段初始化。否则,在该类的静态字段第一次使用之前,以实现相关的时间执行静态字段初始化。
还知道ECMA-334(C#语言规范),静态构造函数,第17.11节
一个非泛型类的静态构造函数在给定应用程序域中最多执行一次。对于从类声明构造的每个封闭构造类型,泛型类声明的静态构造函数最多执行一次(§25.1.5)。触发静态构造函数的执行是由以下事件中发生的第一个事件触发的:- 创建该类的实例。 - 引用了该类的任何静态成员。
如果一个类包含Main方法(§10.1),其中执行开始,则该类的静态构造函数在调用Main方法之前执行。如果一个类包含任何具有初始值设定项的静态字段,则这些初始化器将在执行静态构造函数之前按文本顺序立即执行(§17.4.5)。
更相关的是ECMA-335(CLI规范),类类型定义,第I部分,第8.9.5节。
[...] 这种类型初始化方法的执行时机和触发条件如下:
- 一个类型可以有一个类型初始化方法,也可以没有。
- 一个类型可以被指定为其类型初始化方法具有松散的语义(为了方便起见,我们称之为BeforeFieldInit)。
- 如果标记为BeforeFieldInit,则该类型的初始化程序方法将在第一次访问该类型定义的任何静态字段之前或之后执行。
- 如果未标记为BeforeFieldInit,则该类型的初始化程序方法将在以下情况下触发执行:
a. 访问该类型的任何静态字段时首次访问
b. 调用该类型的任何静态方法时首次调用
c. 如果它是值类型,则调用该类型的任何实例或虚拟方法时首次调用
d. 调用该类型的任何构造函数时首次调用。- 任何类型的初始化程序方法的执行都不会触发自动执行其基类型定义的任何初始化程序方法,也不会触发其实现的任何接口的初始化程序方法。
相关的MSDN链接:
Type.GetField方法
FieldInfo类
FieldInfo.GetValue方法
GetField()
)并不算是"访问"或"引用"实例或类型。但是,一旦调用FieldInfo.GetValue()
,就会算作访问。但这只是我的直觉,缺乏证实,因此没有发布为答案。 - CodeCaster