反映方法(如GetField和GetValue)是否在ECMA规范条款中执行"引用"或"访问"?

Ano*_*ken 7 c# reflection specifications typeinitializer

我真正想知道的是哪种反射方法会触发类型初始化?这对我来说有点不清楚.具体来说,如果应用于静态字段,两个提到的方法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节

[...]触发执行此类型初始化方法的时间和内容的语义如下:

  1. 类型可以具有类型初始化方法或不具有类型初始化方法.
  2. 可以将类型指定为其类型初始化方法具有宽松的语义(为方便起见,我们称之为松弛语义BeforeFieldInit).
  3. 如果标记为BeforeFieldInit,则类型的初始化方法在首次访问为该类型定义的任何静态字段时或之前执行.
  4. 如果未标记为BeforeFieldInit,则执行该类型的初始化方法(即,由以下方式触发):
    a.首先访问该类型的任何静态字段,或
    b.首先调用该类型的任何静态方法,或
    c.如果是值类型或
    d ,则首先调用该类型的任何实例或虚方法 .首次调用该类型的任何构造函数.
  5. 执行任何类型的初始化方法都不会触发自动执行由其基类型定义的任何初始化方法,也不会触发该类型实现的任何接口.

相关的MSDN链接:
Type.GetField方法
FieldInfo类
FieldInfo.GetValue方法

haz*_*zik 1

我真正想知道的是哪些反射方法会触发类型初始化?

[...]

具体来说,如果应用于静态字段,上述两个方法 GetField 和 GetValue 是否会触发类型初始化?

FieldInfo.GetValue触发类型初始化。这是从实验观察得来的。这一切都取决于实施,并且没有证据。它不一定在所有情况下都有效,因为反射不需要遵循任何规范,因为规范不涵盖反射。有一些迹象表明您可以获得未初始化的字段,但我无法生成代码来实现它。

typeof()Type.GetType, 和Type.GetField很可能不会触发类型初始化。但同样,这是来自观察。

如果您需要确保类型初始值设定项将在任何特定时间/之前被调用,则需要调用RuntimeHelpers.RunClassConstructor方法。这是保证类型初始值设定项将被调用的唯一方法,并且在应用程序域的生命周期中仅调用一次。

哪些行为实际上符合“访问”的条件?

这些操作均不适用,因为规范未涵盖反射,因此这些术语不适用于此处。

获取字段的 FieldInfo 元数据是否算作“引用”或“访问”该字段?

两者都不。

从规范中尚不清楚,但这就是我理解“访问”和“引用”之间区别的方式:

  • 访问是当您调用此成员(方法或属性)或获取/设置其值(字段)时
  • 当方法的主体具有对该成员的访问表达式时,该方法将引用该成员。

PS:目前还不清楚你在问什么以及你试图解决什么特定问题。