Недавно вспомнил студенческие годы и про функцию 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.
Никаких ограничений на код этих методов не накладывается. Инициализаторам модуля разрешается выполнять как управляемый, так и неуправляемый код.
Инициализация модуля гарантирует:
- Инициализатор модуля исполняется во время, или через некоторое время до первого обращения к типам, методам или данным, определённым в модуле. Наличие самого инициализатора в модуле необязательно.
- Инициализатор модуля вызывается единожды для каждого модуля, за исключением явного вызова инициализатора кодом пользователя.
- Ни один из методов, вызванных явно или не-явно из инициализатора модуля, не сможет получить доступ к данным, методам или типам, объявленным в модуле, до окончания выполнения кода инициализатора модуля.
Т.к. 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