有一件事我一直想知道static fields
/ constructors
。
static class
首次引用其中一个字段时进行初始化,这很容易。
但CLR如何知道这是第一次?
答案 0 :(得分:3)
CLR维护一个包含已加载的所有类型及其初始化状态的表。如果A
使用B
的静态字段,则CLR知道A
正在使用B
,并且在初始化A
时,它也会初始化B
}。因此,不会对每次访问执行是否初始化依赖项的检查。通过类型的依赖图确保它。
如果您对实施细节感兴趣,可以查看CoreCLR中IsClassInitialized
的{{1}}方法及其usage时创建类实例的方法
我希望这能回答你的问题。
答案 1 :(得分:2)
第一次引用其中一个字段时
static class
初始化,这很容易。
不,这不是那么简单。如果忽略方法调用,则static
类必须在第一次访问其中一个字段之前初始化,如果它未标记为beforefieldinit
。如果它标记为beforefieldinit
,则可以在此之前初始化它。 (Jon Skeet有an article with lots more information about beforefieldinit
。)
这会影响何时检查类初始化?由于CLR使用JIT编译,因此它在JIT编译方法时检查类初始化。如果该类标记为beforefieldinit
且尚未初始化,则JIT编译器会立即对其进行初始化。然后它实际上编译了方法,它可以假定该类已经初始化,因此不需要检查。
如果没有beforefieldinit
,如果类尚未初始化,则JIT编译器必须发出代码,在每次潜在的第一次字段访问之前检查初始化。但是如果该类已经初始化并且另一个方法正在编译JIT,则JIT编译器不再需要在那里发出检查。
在某些情况下,这会对性能产生负面影响。从上面可以清楚地看到,要防止出现这种情况,您需要确保将有问题的类标记为beforefieldinit
。从C#开始的方法是没有static
构造函数,只使用static
字段初始值设定项。