beforefieldinit 标志有什么作用?当我查看班级的 IL 时,我看到了这个标志,但我不知道这个标志实际上在做什么?
4 回答
请参阅我关于这个问题的文章。
基本上,beforefieldinit
意味着“可以在引用任何静态字段之前的任何时候初始化类型。” 从理论上讲,这意味着它可以非常延迟地初始化——如果你调用一个不涉及任何字段的静态方法,JIT 就不需要初始化类型。
实际上,这意味着该类的初始化时间比其他情况要早-可以在可能使用它的第一个方法开始时对其进行初始化。将此与未beforefieldinit
应用于它们的类型进行比较,其中类型初始化必须在第一次实际使用之前立即发生。
所以,假设我们有:
public static void DoSomething(bool which)
{
if (which)
{
FirstType.Foo();
}
else
{
SecondType.Bar();
}
}
如果这两种类型都beforefieldinit
应用于它们(在 C# 中默认情况下它们会应用,除非该类型具有静态构造函数),那么它们都将在方法开始时被初始化DoSomething
(通常 - 不能保证)。如果他们没有,beforefieldinit
那么只有其中一个会被初始化,基于标志。
这就是为什么在实现单例模式时通常使用静态构造函数(甚至是空的构造函数!)的原因。
如果标记为 BeforeFieldInit,则该类型的初始化方法在第一次访问为该类型定义的任何静态字段时或之前的某个时间执行。
如果未标记 BeforeFieldInit,则在第一次访问该类型的任何静态或实例字段或首次调用该类型的任何静态、实例或虚拟方法时执行该类型的初始化方法。
当类型声明显式静态构造函数时,即时 (JIT) 编译器会对该类型的每个静态方法和实例构造函数添加检查,以确保先前调用了静态构造函数。当访问任何静态成员或创建该类型的实例时,将触发静态初始化。但是,如果您声明该类型的变量但不使用它,则不会触发静态初始化,这在初始化更改全局状态时可能很重要。
当所有静态数据都内联初始化并且未声明显式静态构造函数时,Microsoft 中间语言 (MSIL) 编译器将beforefieldinit
标志和用于初始化静态数据的隐式静态构造函数添加到 MSIL 类型定义。
当 JIT 编译器遇到 beforefieldinit 标志时,大多数时候不会添加静态构造函数检查。静态初始化保证在访问任何静态字段之前的某个时间发生,但不会在调用静态方法或实例构造函数之前发生。请注意,静态初始化可以在声明该类型的变量后的任何时间发生。
静态构造函数检查会降低性能。通常静态构造函数仅用于初始化静态字段,在这种情况下,您必须确保静态初始化发生在第一次访问静态字段之前。beforefieldinit 行为适用于这些和大多数其他类型。仅当静态初始化影响全局状态并且以下情况之一为真时才不合适:
对全局状态的影响是昂贵的,如果不使用该类型,则不需要。
无需访问该类型的任何静态字段即可访问全局状态效果。
有关更多信息 https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1810