【问题标题】:Module initializers in C#C# 中的模块初始化器
【发布时间】:2010-12-27 07:04:48
【问题描述】:

模块初始化器是 CLR 的一项功能,在 C# 或 VB.NET 中不直接可用。它们是名为.cctor 的全局静态方法,保证在执行程序集中的任何其他代码(类型初始化程序、静态构造函数)之前运行。我最近想在一个项目中使用它并 hacked together my own solution (console program/msbuild task) 使用 Mono.Cecil,但我想知道:

  1. 有什么办法可以诱使 C# 编译器发出模块初始化程序?是否有任何属性(例如 CompilerGenerated、SpecialName)或其他可以使用的技巧?

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

【问题讨论】:

标签: c# clr clr-module-initializer


【解决方案1】:

查看由 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();
}

【讨论】:

  • 感谢您的建议。这实际上是基于我在提出这个问题后编写的自己的代码。 Simon Cropp 然后将其改编为他出色的 Fody 项目的插件。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    【讨论】:

    • 您能否详细说明源生成器如何启用模块初始化?乍一看,它们似乎是 2 个不同的特征。
    • "代码生成器的第二个新特性是模块初始化器。模块初始化器是附加了 ModuleInitializerAttribute 属性的方法。这些方法将由运行时在任何其他字段访问或方法调用之前调用整个模块。”
    • 代码生成器只是使模块初始化器成为可能的工具
    • 我不太理解你的推理。代码生成器是与模块初始化器完全不同的功能,它们的工作方式完全不同。模块初始化器是通过特定于该目的的属性启用的。是的,您可以使用生成器将初始化程序嵌入到其他人的模块中,但这是完全不同的。
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      埃纳尔, 您的问题没有让我清楚地知道您已经编写了一个工具,该工具允许将模块初始化程序注入到已编译的程序集中。

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

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

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

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

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

      【讨论】:

      • .NET 程序集通常是延迟加载的。含义:您认为模块初始化程序在程序集加载后的某个时间执行的假设可能不正确。只是程序集仅在需要时才加载,不是在应用程序启动时立即加载。
      • 也许我不够清楚。我说的是通过 Assembly.Load() 将 C# DLL 加载到 C# 进程中。在这种情况下,不执行初始化程序。我正在寻找 C++ 中 DllMain() 的等效项,当 DLL 加载到进程中时会立即执行。
      • 啊,我明白了。那就奇怪了。
      【解决方案6】:

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

      【讨论】:

      • 它会在您定义静态构造函数的类中发出 .cctor,是的,但这只是该类的静态构造函数,将在第一次访问该类时运行。模块初始化程序是伪 类上的 .cctor,保证在程序集中的任何其他代码之前运行,无论首先访问什么代码。
      猜你喜欢
      • 1970-01-01
      • 2011-02-14
      • 2020-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-17
      • 1970-01-01
      • 2018-02-13
      相关资源
      最近更新 更多