模块初始值设定项是CLR的一项功能,无法在C#或VB.NET中直接使用。它们是名为.cctor
的全局静态方法,它们保证在执行程序集中的任何其他代码(类型初始化程序,静态构造函数)之前运行。我最近想在项目中使用它,hacked together my own solution (console program/msbuild task)使用Mono.Cecil,但我想知道:
有没有办法欺骗C#编译器发出模块初始化器?是否有任何属性(例如CompilerGenerated,SpecialName)或其他可以使用的技巧?
C#/ VB.NET是否会为某些目的自行发出这些初始值设定项?从我所看到的它们被托管C ++用于某些互操作目的,但我找不到任何引用它们用于其他目的。有什么想法吗?
答案 0 :(得分:10)
查看由Simon Cropp撰写的令人敬畏的开源IL-Weaver项目“fody”的模块初始化程序插件:https://github.com/fody/moduleinit
它允许您指定一个方法,该方法将由fody转换为汇编初始值设定项:
public static class ModuleInitializer
{
public static void Initialize()
{
//Init code
}
}
得到这个:
static <Module>()
{
ModuleInitializer.Initialize();
}
答案 1 :(得分:8)
不,没有办法在C#中发出它们,因为C#将所有内容放在类/结构中,模块初始值设定项需要是全局的。
您必须使用其他工具编写它们,最好是IL-Assembler。
关于第二个问题,我必须承认我不知道,但我从未见过任何由C#生成的,并且我经常使用ILDasm,所以我认为它不会发出它们。
答案 2 :(得分:3)
也许System.Reflection.Emit
命名空间可以帮助您。 MethodAttributes
枚举包含类似的元素(SpecialName, RTSpecialName)
。
答案 3 :(得分:2)
十一年后,C#9语言终于支持了这一点
https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9#support-for-code-generators
答案 4 :(得分:1)
埃纳尔, 您的问题并没有告诉我您已经编写了一个工具,允许将模块初始化程序注入已编译的程序集中。
http://einaregilsson.com/module-initializers-in-csharp
我尝试了你的应用程序,它完美无缺。 在您编写时,它应该适用于从2到4.5的所有当前框架。
只有一个问题会让您的解决方案对我无用: 当应用程序首次访问程序集中的任何内容时,将调用初始化程序。
我需要的是在将程序集加载到进程中时应立即调用模块初始值设定项。但事实并非如此。因此,如果应用程序不访问程序集,它将永远不会被初始化。
在调查了一整天之后,在我看来,获得此功能的唯一方法是编写托管C ++程序集并在DllMain()中执行代码。
答案 5 :(得分:-5)
如果你有静态构造函数或单例类,你可以访问true,静态变量C#编译器会发出.cctor。