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

  1. 有什么方法可以欺骗 C# 编译器发出模块初始化程序吗?任何属性(例如CompilerGenerate, SpecialName) 或其他可以使用的技巧?

  2. C# / VB.NET 是否出于某种目的自行发出这些初始化程序?据我所知,托管 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。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top