Инициализаторы модулей на C#
-
20-09-2019 - |
Вопрос
Инициализаторы модулей - это функция среды CLR, которая недоступна непосредственно в C # или VB.NET.Это глобальные статические методы с именем .cctor
которые гарантированно выполняются до выполнения любого другого кода (инициализаторов типов, статических конструкторов) в сборке.Недавно я хотел использовать это в проекте и взломал мое собственное решение (консольная программа / задача msbuild) использую Mono.Сесил, но мне было интересно:
Есть ли какой-нибудь способ обмануть компилятор C #, чтобы он выдавал инициализаторы модулей?Любые атрибуты (например,CompilerGenerated, SpecialName) или другой трюк, который можно было бы использовать?
Использует ли C # / VB.NET когда-либо сами эти инициализаторы для какой-либо цели?Из того, что я видел, они используются managed C ++ для некоторых целей взаимодействия, но я не смог найти никаких ссылок на то, что они используются для других целей.Есть какие-нибудь идеи?
Решение
Нет, в C# их невозможно создать, поскольку C# помещает все в класс/структуру, а инициализаторы модулей должны быть глобальными.
Для их написания вам придется использовать другой инструмент, желательно IL-Assembler.
Что касается второго вопроса, я должен признаться, что не знаю, но я никогда не видел, чтобы C# генерировал их, и я использую ILDasm довольно часто, поэтому предполагаю, что он их не генерирует.
Другие советы
Ознакомьтесь с надстройкой инициализатора модуля замечательного проекта IL-Weaver с открытым исходным кодом "фоди", написано Саймоном Кроппом: 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.