Модуль инициализаторы в C#
Инициализаторы модулей - это функция CLR, которая не доступна напрямую в C# или VB.NET. Это глобальные статические методы, названные .cctor
которые гарантированно выполняются перед выполнением любого другого кода (инициализаторы типов, статические конструкторы) в сборке. Недавно я хотел использовать это в проекте и взломал собственное решение (консольная программа / задача msbuild), используя Mono.Cecil, но мне было интересно:
Есть ли способ обмануть компилятор C# в инициализаторах излучающих модулей? Какие-нибудь атрибуты (например, CompilerGenerated, SpecialName) или другие хитрости, которые можно использовать?
Вызывает ли когда-нибудь C# / VB.NET сами эти инициализаторы для какой-то цели? Из того, что я видел, они используются управляемым C++ для некоторых целей взаимодействия, но я не смог найти никаких ссылок на их использование для других целей. Есть идеи?
5 ответов
Нет, в C# нет возможности их излучать, потому что C# помещает все в класс / структуру, и инициализаторы модуля должны быть глобальными.
Для их написания вам понадобится другой инструмент, предпочтительно IL-Assembler.
Что касается второго вопроса, я должен признать, что я не знаю, но я никогда не видел ни одного сгенерированного C#, и я использую ILDasm довольно часто, поэтому я предполагаю, что он их не генерирует.
Спустя одиннадцать лет это наконец-то поддерживается языком C#9.
https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9#support-for-code-generators
Посмотрите модуль инициализатора дополнения к удивительному проекту IL-Weaver с открытым исходным кодом " fody", написанному Симоной Кропп: https://github.com/fody/moduleinit
Это позволяет вам указать метод, который будет переведен в инициализатор сборки fody:
public static class ModuleInitializer
{
public static void Initialize()
{
//Init code
}
}
получает это:
static <Module>()
{
ModuleInitializer.Initialize();
}
Может быть System.Reflection.Emit
Пространство имен может помочь вам. MethodAttributes
перечисление содержит похожие элементы (SpecialName, RTSpecialName)
,
Einar, Ваш вопрос не прояснил мне, что вы уже написали инструмент, который позволяет внедрить инициализатор модуля в уже скомпилированную сборку.
http://einaregilsson.com/module-initializers-in-csharp
Я попробовал ваше приложение, и оно отлично работает. Как вы пишете, он должен работать со всеми текущими фреймворками от 2 до 4.5.
Есть только одна проблема, которая делает ваше решение бесполезным для меня: ваш инициализатор вызывается, когда приложение впервые ДОСТУПАЕТ что-либо в сборке.
Что мне нужно, так это то, что инициализатор модуля должен вызываться сразу, когда сборка загружается в процесс. Но это не так. Поэтому, если приложение не обращается к сборке, оно никогда не будет инициализировано.
После целого дня исследования мне кажется, что единственный способ добиться этого - написать управляемую сборку C++ и выполнить код в DllMain().
Если у вас есть статические конструкторы или одноэлементные классы, к которым вы можете получить доступ в true, компилятор статической переменной C# выдаст.cctor.