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

от автора

Недавно вспомнил студенческие годы и про функцию 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 

ссылка на оригинал статьи http://habrahabr.ru/post/175185/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *