Module initializers(模块初始化器)是一个在C#或VB.NET中无法直接使用的特性。它们是名为.cctor
的全局静态方法,保证在程序集中的任何其他代码(类型初始化器,静态构造函数)执行之前运行。我最近想在一个项目中使用这个,并使用Mono.塞西尔的hacked together my own solution (console program/msbuild task),但我想知道:
1.有什么方法可以欺骗C#编译器发出模块初始化器吗?有什么属性(例如,Generated,SpecialName)或其他可以使用的技巧吗?
- C# / VB.NET是否为了某种目的而发出这些初始化器?据我所知,托管C++为了某些互操作目的而使用它们,但我找不到任何关于它们用于其他目的的参考。有什么想法吗?
6条答案
按热度按时间14ifxucb1#
11年后,C#9语言终于支持了这一点
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9#support-for-code-generators
模块初始化器是附加了
ModuleInitializerAttribute
属性的方法。这些方法将在整个模块中的任何其他字段访问或方法调用之前由运行时调用。模块初始化器方法:最后一个要点实际上意味着该方法及其包含的类必须是内部或公共的。该方法不能是局部函数。有关更多信息,请参见ModuleInitializer属性。
kr98yfug2#
查看由Simon Cropp编写的非常棒的开源IL-Weaver项目“fody“的模块初始化器插件:https://github.com/fody/moduleinit
它允许你指定一个方法,该方法将被fody转换为一个汇编初始化器:
字符串
得到这个:
型
3pvhb19x3#
不,在C#中没有办法发出它们,因为C#将所有内容放在类/结构中,并且模块初始化器需要是全局的。
你将不得不使用不同的工具来编写它们,最好是IL-Assembler。
至于第二个问题,我不得不承认我不知道,但我从来没有见过任何由C#生成的,我经常使用ILDasm,所以我假设它不会发出它们。
hiz5n14c4#
也许
System.Reflection.Emit
命名空间可以帮助你。MethodAttributes
枚举包含类似的元素(SpecialName, RTSpecialName)
。rggaifut5#
Einar,你的问题没有让我清楚你已经写了一个工具,允许将模块初始化器注入到已经编译的程序集中。
http://einaregilsson.com/module-initializers-in-csharp
我试过你的应用程序,它工作得很好。当你写它应该与所有当前的框架从2到4.5工作。
只有一个问题使你的解决方案对我没用:当应用程序第一次访问程序集中的任何东西时,你的初始化器被调用。
我需要的是模块初始化器应该在程序集加载到进程中时立即被调用。但它不是。所以如果应用程序不访问程序集,它将永远不会被初始化。
在研究了一整天之后,在我看来,获得这一点的唯一方法是编写托管C++程序集并在DllMain()中执行代码。
m3eecexj6#
如果你有静态构造函数或单例类,你可以访问true,一个静态变量C#编译器将发出. cctor。