📜 ⬆️ ⬇️

Brief description of module initializers in .Net

Recently I remembered my student years and about the dllmain function, after which I wondered - is there something similar in .Net?
As it turned out, there is, but not all the languages ​​of this little family are supported. This post is a translation of a short (but informative) article on this topic.


In CLR versions 1.0 and 1.1. type initializers are supported. Many are familiar with them, but just in case, I’ll provide a squeeze from ECMA-335: CLR Section 2 Metadata and file format:

A type (class, interface, value type) can have a special method called a type initializer, which is used to initialize the type itself (it is called when it is first accessed that type, and not during the loading of the assembly itself - note translated ). The method must be static, have 0 parameters and not have a return type, must be marked as rtspecialname and specialname, and must be named .cctor.
')
Like instance constructors, type initializers can write to static fields of other types with the initonly attribute.

.class public EngineeringData extends [mscorlib]System.Object { .field private static initonly float64[] coefficient .method private specialname rtspecialname static void .cctor() cil managed { .maxstack 1 // allocate array of 4 Double ldc.i4.4 newarr [mscorlib]System.Double // point initonly field to new array stsfld float64[] EngineeringData::coefficient // code to initialize array elements goes here ret } } 


Comment
Type initializers are usually methods that initialize fields with constants or using simple calculations. However, there are no restrictions on the code of these methods.


CLR version 2.0, in turn, provides module initializers. They are similar to type initializers, with the only difference that the module initializer is associated with a module, not a type. Since it is not associated with a type; it is a global function.

Description of the module initializer:

A module may contain a special method called a module initializer for the purpose of self-initializing a module.
All modules can have an initializer. The method must be static, a member of the module, take 0 parameters, have no return type, be marked as rtspecialname and specialname, and have the name .cctor.
There are no restrictions on the code of these methods. Module initializers are allowed to execute both managed and unmanaged code.

Module initialization guarantees:
  1. The module initializer is executed during, or some time before, the first access to the types, methods or data defined in the module. The presence of the initializer itself in the module is optional.
  2. A module initializer is called once for each module, except for explicitly calling the initializer by a user code.
  3. None of the methods called explicitly or non-explicitly from the module initializer will be able to access data, methods or types declared in the module until the end of the module initializer code execution.

Since C # has no global functions, the creation of module initializers is not available in it.

As described in the MSDN VC ++ chat , C ++ / CLI internally uses module initializers. ( C ++ / CLI internally uses module initializer, as described in MSDN VC ++ chat script. )

The following code is a decompile in ildasm of the msvcm80.dll module:

 .method assembly specialname rtspecialname static void .cctor() cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerStepThroughAttribute::.ctor() = ( 01 00 00 00 ) // Code size 39 (0x27) .maxstack 2 .locals ([0] valuetype '<CrtImplementationDetails>'.LanguageSupport languageSupport) IL_0000: ldloca.s languageSupport IL_0002: call valuetype '<CrtImplementationDetails>'.LanguageSupport* modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall) '<CrtImplementationDetails>.LanguageSupport.{ctor}'(valuetype '<CrtImplementationDetails>'.LanguageSupport* modopt([mscorlib]System.Runtime.CompilerServices.IsConst) modopt([mscorlib]System.Runtime.CompilerServices.IsConst)) IL_0007: pop .try { IL_0008: ldloca.s languageSupport IL_000a: call void modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall) '<CrtImplementationDetails>.LanguageSupport.Initialize'(valuetype '<CrtImplementationDetails>'.LanguageSupport* modopt([mscorlib]System.Runtime.CompilerServices.IsConst) modopt([mscorlib]System.Runtime.CompilerServices.IsConst)) IL_000f: leave.s IL_001f } // end .try fault { IL_0011: ldftn void modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall) '<CrtImplementationDetails>.LanguageSupport.{dtor}'(valuetype '<CrtImplementationDetails>'.LanguageSupport* modopt([mscorlib]System.Runtime.CompilerServices.IsConst) modopt([mscorlib]System.Runtime.CompilerServices.IsConst)) IL_0017: ldloca.s languageSupport IL_0019: call void ___CxxCallUnwindDtor(method void *(void*), void*) IL_001e: endfinally } // end handler IL_001f: ldloca.s languageSupport IL_0021: call void modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall) 'gcroot<System::String ^>.{dtor}'(valuetype 'gcroot<System::String ^>'* modopt([mscorlib]System.Runtime.CompilerServices.IsConst) modopt([mscorlib]System.Runtime.CompilerServices.IsConst)) IL_0026: ret } // end of method 'Global Functions'::.cctor 

Source: https://habr.com/ru/post/175185/


All Articles