我真正想知道的是哪种反射方法会触发类型初始化?这对我来说有点不清楚。具体来说,如果应用于静态字段,两个提到的方法GetField和GetValue会触发类型初始化吗?我已经尝试过调查此事,据我所知,执行诸如引用或访问静态字段之类的操作将触发所有静态字段的类型初始化。下面我引用了我认为相关的规范部分,但是使用诸如“引用”和“访问”之类的措辞正是我犹豫不决的地方:
什么行动实际上被称为“访问”?
获取字段的FieldInfo元数据是否计为“引用”或“访问”字段?
请帮我找到规格的相关部分,以便我知道我的代码*是安全的和规范。因为一些未记录的实现细节,或者因为行星碰巧恰好对齐,所以并不是简单地“碰巧工作”。
*我的代码通过测试,但依赖于类型初始化行为。我的代码没有在这里显示,因为它是冗长的,问题不是关于我只是想要“你的代码看起来没问题”回复,而是我想知道如何以及为什么这样我可以评估我的代码是否是规范。是否符合我自己的要求,并且(假设它是合规的)我可以做出什么改变的理由,而不必在每次我都这样做的时候提出新的问题。
到目前为止,我知道以下几个规范,它们使用上述术语“引用”和“访问”:
我知道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,则执行该类型的初始化方法(即,由以下方式触发):
一个。首先访问该类型的任何静态字段,或
湾首次调用该类型的任何静态方法,或
℃。首先调用该类型的任何实例或虚方法(如果它是值类型或)
d。首次调用该类型的任何构造函数。- 执行任何类型的初始化方法都不会触发自动执行由其基类型定义的任何初始化方法,也不会触发该类型实现的任何接口。
醇>
相关的MSDN链接:
Type.GetField Method
FieldInfo Class
FieldInfo.GetValue Method
答案 0 :(得分:1)
我真正想知道的是哪种反射方法会触发类型初始化?
[...]
具体来说,如果应用于静态字段,两个提到的方法GetField和GetValue会触发类型初始化吗?
FieldInfo.GetValue
触发类型初始化。它来自实验观察。这完全取决于实现,并且没有证据。它并不一定适用于所有情况,因为Reflection不需要遵循任何规范,因为规范不涉及反射。有一些signs你可以获得一个未初始化的字段,但我无法生成代码来实现它。
typeof()
,Type.GetType
和Type.GetField
很可能不会触发类型初始化。但同样,这是一次观察。
如果您需要确保在任何特定时间/之前调用您的类型初始值设定项,则需要调用RuntimeHelpers.RunClassConstructor
方法。这是唯一一种方法,可以保证在应用程序域的生命周期内只调用一次类型初始值设定项。
实际上哪些行为符合"访问"?
这些操作都没有,因为规格不包含反射,因此这些术语不适用于此处。
将字段的FieldInfo元数据计为"引用"或者"访问"这个领域?
都不是。
规范中并不清楚,但这就是我理解"访问"之间的区别。和"引用":