26

模块初始值设定项是 CLR 的一项功能,在 C# 或 VB.NET 中不直接可用。它们是命名的全局静态方法.cctor,保证在程序集中的任何其他代码(类型初始值设定项、静态构造函数)执行之前运行。我最近想在一个项目中使用它,并使用 Mono.Cecil 编写了我自己的解决方案(控制台程序/msbuild 任务) ,但我想知道:

  1. 有没有办法欺骗 C# 编译器发出模块初始化程序?任何可以使用的属性(例如 CompilerGenerated、SpecialName)或其他诡计?

  2. C# / VB.NET 是否曾经出于某种目的自己发出这些初始化程序?从我所看到的情况来看,托管 C++ 将它们用于某些互操作目的,但我找不到任何关于它们被用于其他目的的引用。有任何想法吗?

4

6 回答 6

13

查看由 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();
}
于 2013-06-29T10:49:41.947 回答
9

不,没有办法在 C# 中发出它们,因为 C# 将所有内容都放在类/结构中,并且模块初始化程序需要是全局的。

您将不得不使用不同的工具来编写它们,最好是 IL-Assembler。

至于第二个问题,我不得不承认我不知道,但我从未见过 C# 生成的,而且我经常使用 ILDasm,所以我假设它不会发出它们。

于 2009-12-16T15:53:50.453 回答
7

十一年后,这终于得到了 C#9 语言的支持

https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9#support-for-code-generators

于 2020-11-14T01:53:01.800 回答
3

也许System.Reflection.Emit命名空间可以帮助你。MethodAttributes枚举包含相似的元素(SpecialName, RTSpecialName)

于 2011-07-24T21:50:21.047 回答
1

Einar,您的问题并没有让我明白您已经编写了一个工具,该工具允许将模块初始化程序注入到已编译的程序集中。

http://einaregilsson.com/module-initializers-in-csharp

我尝试了您的应用程序,它运行良好。在您编写时,它应该适用于从 2 到 4.5 的所有当前框架。

只有一个问题使您的解决方案对我无用:当应用程序首次访问程序集中的任何内容时,将调用您的初始化程序。

我需要的是在将程序集加载到进程中时应立即调用模块初始化程序。但事实并非如此。因此,如果应用程序不访问程序集,它将永远不会被初始化。

在调查了一整天之后,在我看来,唯一的方法是编写一个托管 C++ 程序集并在 DllMain() 中执行代码。

于 2015-02-11T21:41:55.410 回答
-5

如果您有静态构造函数或可以访问 true 的单例类,则静态变量 C# 编译器将发出 .cctor。

于 2009-12-17T03:07:50.197 回答