【发布时间】:2017-06-01 16:28:28
【问题描述】:
我真正想知道的是哪些反射方法会触发类型初始化?我有点不清楚。具体来说,如果将上述两个方法 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 规范),类类型定义,第一部分,第 8.9.5 节
[...] 触发此类初始化方法执行的时间和内容的语义如下:
- 类型可以有类型初始化方法,也可以没有。
- 可以将类型指定为其类型初始化器方法具有宽松语义(为了下面的方便,我们将这种宽松语义称为 BeforeFieldInit)。
- 如果标记为 BeforeFieldInit,则该类型的初始化方法会在首次访问为该类型定义的任何静态字段时或之前的某个时间执行。
- 如果未标记 BeforeFieldInit,则该类型的初始化方法在以下位置执行(即由以下位置触发):
一个。首次访问该类型的任何静态字段,或
乙。首次调用该类型的任何静态方法,或
c。如果它是值类型,则首次调用该类型的任何实例或虚拟方法,或者
d.首次调用该类型的任何构造函数。- 执行任何类型的初始化方法都不会触发由其基类型定义的任何初始化方法的自动执行,也不会触发该类型实现的任何接口。
相关 MSDN 链接:
Type.GetField Method
FieldInfo Class
FieldInfo.GetValue Method
【问题讨论】:
-
这如何保证对“基于意见”的密切投票?规格有时会令人困惑,我只想知道我是否正确解释了它们。如果幸运的话,其中一位设计师会回答它,因此不会有任何基于意见的内容。
-
是的,这是一个奇怪的接近投票。无论如何,反射不在 C# 规范的范围之内,因为它是 CLI 的东西,而不是 C# 的东西。反射方法调用基本上是指示运行时发出和/或执行相关的 IL,这反过来又调用适当主题的 C# 规范中的相关规则,例如类型初始化,其中 C# 和 CLI 之间的重叠很重(基本上是C# 规范承诺 CLI 的东西,而不是 C# 特定的东西)。但这只是我头脑中的一个解释,我真的找不到更准确的解释来源。
-
好吧,我想说仅仅检查类型信息(例如
GetField())并不能算作“访问”或“引用”实例或类型,但是只要你打电话给FieldInfo.GetValue(),它就可以了。但这是一种未受过教育的直觉,我无法确认,因此没有作为答案发布。 -
单独检查 Type 对象不会触发此构造函数,也不会检查字段、属性、方法或类型本身的属性。
-
@hazzik 我刚刚重读了您的题外话链接。对我来说似乎很有话题。也许自从你上次自己阅读后它已经被修改过? “如果您的问题通常涵盖软件开发特有的实际、可回答的问题,那么您来对地方提出问题了!”据我所知,该声明之后的任何警告均不适用。 (但感谢您抽出宝贵时间发表评论,这很有帮助,如果我错了,我想了解原因。)
标签: c# reflection specifications typeinitializer