Краткое описание инициализаторов модулей в .Net

в 16:25, , рубрики: .net, dllmain, инициализаторы, Программирование

Недавно вспомнил студенческие годы и про функцию dllmain, после чего задумался — есть ли нечто подобное в .Net?
Как оказалось, есть, но не всеми языками этой семейки поддерживается. Этот пост является переводом короткой (но содержательной) статьи по этой теме.

В CLR версий 1.0 и 1.1. Поддерживаются инициализаторы типов. Многие с ними знакомы, но на всякий случай предоставлю выжимку из ECMA-335: CLR Раздел 2 Метаданные и формат файла:

Тип (класс, интерфейс, тип значения) может иметь специальный метод называемый инициализатором типа, который используется чтобы инициализировать сам тип (при этом, вызывается при первом обращении к этому типу, а не во время загрузки самой сборки — прим. перев.). Метод должен быть статическим, иметь 0 параметров и не иметь возвращаемого типа, должен быть помечен как rtspecialname и specialname, и должен называться .cctor.

Подобно конструкторам экземпляра, инициализаторы типа могут писать в статические поля других типов с атрибутом initonly.

.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
  }
}
Замечание

Инициализаторами типов обычно являются методы, которые инициализируют поля константами или с помощью простых вычислений. Впрочем, никаких ограничений на код этих методов не накладывается.

CLR версии 2.0, в свою очередь, предоставляет инициализаторы модуей. Аналогичны инициализаторам типа, с тем лишь отличием что инициализатор модуля ассоциируется с модулем, а не типом. Т.к. он не ассоциирован с типом, он является глобальной функцией.

Описание инициализатора модуля:

Модуль может содержать специальный метод, называемый инициализатором модуля в целях самостоятельной инициализации модуля.
Все модули могут иметь инициализатор. Метод должен быть статичным, членом модуля, принимать 0 параметров, не иметь возвращаемого типа, быть помеченным как rtspecialname и specialname, и иметь имя .cctor.
Никаких ограничений на код этих методов не накладывается. Инициализаторам модуля разрешается выполнять как управляемый, так и неуправляемый код.

Инициализация модуля гарантирует:

  1. Инициализатор модуля исполняется во время, или через некоторое время до первого обращения к типам, методам или данным, определённым в модуле. Наличие самого инициализатора в модуле необязательно.
  2. Инициализатор модуля вызывается единожды для каждого модуля, за исключением явного вызова инициализатора кодом пользователя.
  3. Ни один из методов, вызванных явно или не-явно из инициализатора модуля, не сможет получить доступ к данным, методам или типам, объявленным в модуле, до окончания выполнения кода инициализатора модуля.

Т.к. C# не имеет глобальных функций, создание инициализаторов модуля в нём недоступно.

Как описано в чате MSDN VC++, C++/CLI внутренне использует инициализаторы модулей. (C++/CLI internally uses module initializer, as described in the MSDN VC++ chat script.)

Следующий код является декомпилом в ildasm модуля msvcm80.dll:

.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

Автор: 6opoDuJIo

Источник

Поделиться

* - обязательные к заполнению поля