Модуль инициализаторы в C#

Инициализаторы модулей - это функция CLR, которая не доступна напрямую в C# или VB.NET. Это глобальные статические методы, названные .cctor которые гарантированно выполняются перед выполнением любого другого кода (инициализаторы типов, статические конструкторы) в сборке. Недавно я хотел использовать это в проекте и взломал собственное решение (консольная программа / задача msbuild), используя Mono.Cecil, но мне было интересно:

  1. Есть ли способ обмануть компилятор C# в инициализаторах излучающих модулей? Какие-нибудь атрибуты (например, CompilerGenerated, SpecialName) или другие хитрости, которые можно использовать?

  2. Вызывает ли когда-нибудь 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.

Другие вопросы по тегам