Beforefieldinit and class static Constructor
Luo chaohui (http://kesalin.cnblogs.com /)
This article follows the "signature-non-commercial use-consistency" creation public agreement
As follows:Code:
Using System; Namespace Beforefieldinit { Internal Class Foo {Foo () {console. writeline ( " Foo object constructor " );} Public Static String Field = getstring ( " Initialize the foo static member variable! " ); Public Static String Getstring ( String S) {console. writeline (s ); Return S ;}} Internal Class Foostatic { Static Foostatic () {console. writeline ( " Foostatic class Constructor " );} Foostatic () {console. writeline ( " Foostatic object constructor " );} Public Static String Field = getstring ( " Initialize the foostatic static member variable! " ); Public Static String Getstring ( String S) {console. writeline (s ); Return S ;}} Class Program { Static Void Main ( String [] ARGs) {console. writeline ( " Start with main... " ); Foo. getstring ( " Manually call Foo. getstring! " ); // String info = Foo. field; Foostatic. getstring ( " Manually call foostatic. getstring! " ); // String infostatic = foostatic. field; Console. Readline ();}}}
The only difference between Foo and foostatic is that foostatic has a static class constructor. Execute the above Code and output the following:
If you open the two lines of code that have been commented out to read the static field, compile and run the code, and output:
Compared with the above differences, foostatic always delays loading, that is, only when the class is used for the first time, the class object is constructed, and its static members and static constructors are initialized and executed, the initialization of the foo class object is decided by CLR.
If we use il dasm.exe to compare the intermediate code generated by the two classes, we can see that there is only one difference: foostatic has one feature less than FOO: beforefieldinit.
That is to say, the static constructor suppresses the beforefieldinit feature, which affects the time to call this class.
The static constructor in C #, also known as the Type constructor, is private and is in. cctor: void (). CLR ensures that a static constructor is executed only once in each appdomain, and such execution is thread-safe, therefore, static constructor is very suitable for single-instance Mode Initialization (initializing static fields is equivalent to initializing in static constructor, but not exactly the same, because the explicit definition of the static constructor will suppress the beforefieldinit flag .).
When compiling a method, the JIT compiler will check which types are referenced in the Code. If any type defines a static constructor, the JIT compiler will check for the current appdomain, whether the static constructor is executed. If the Type constructor is not executed, the JIT compiler will add a call to the static constructor in the generated local code. Otherwise, it will not be added because the type has been initialized. At the same time, CLR also ensures the thread security of the static constructor code generated during local code execution.
According to the above description, we know that JIT must determine whether to generate static constructor code and when to call it. There are two methods to call a specific call:
Precise: The JIT compiler can produce this call just before the first instance of the type is created, or before a non-inherited field or member of the JIT class.
Beforefieldinit: The JIT compiler can generate a call at any time before accessing a static field or a static/instance method for the first time, or before creating the first instance of the type. The specific call time is determined by the CLR. It only ensures that the static constructor will be executed before accessing the Members, but may be executed very early.
CLI specification (ECMA 335) mentioned in section 8.9.5:
- If marked beforefieldinit then the type's initializer method is executed at, or sometime before, first access to any static field defined for that type
- If not marked beforefieldinit then that type's initializer method is executed at (I. e., is triggered ):
- First access to any static or instance field of that type, or
- First invocation of any static, instance or virtual method of that type
To put it simply, beforefieldinit may call a type of static constructor in advance, while the precise mode is a non-static constructor of the type that is called only when it is used, which is a strict delayed loading.
Beforefieldinit is the first choice (this is the default method if there is no custom static constructor), because it enables CLR to freely choose the time to call static constructor, the CLR will use this to generate code that runs faster. For example, if you call a singleton (including the first call) in a loop, the beforefieldinit method allows the CLR to call the static constructor before the loop to optimize it, in precise mode, the static constructor is called only in the loop body, and the subsequent calls will detect whether the static constructor has been executed, which is less efficient. When static field is used previously, the CLR in beforefieldinit mode also thinks that it is better to execute the static constructor in advance.
C # Singleton implementation, you can use the precise delay to call this point to delay the construction of Singleton objects (Ele. Me Khan mode), resulting in a little bit of optimization, however, in most cases, this tiny bit of optimization is not very useful!