【问题标题】:Initialize library on Assembly load在程序集加载时初始化库
【发布时间】:2010-10-02 08:29:24
【问题描述】:

我有一个 .net 库 dll,其作用类似于函数库。除了静态方法之外,还有一堆静态类型。

我需要运行一些初始化代码来设置库以供使用。

当程序集被加载时,有没有办法确保运行特定的方法?类似于 AppDomain.AssemblyLoad 但从程序集本身自动调用的东西。我在想也许可以使用类似 AssemblyAttribute 的东西?

目前我在静态构造函数中有此初始化代码,但由于这是一个具有许多入口点的库,因此无法保证会使用此特定类型。

谢谢!

【问题讨论】:

    标签: c# .net assemblies


    【解决方案1】:

    为什么您需要在使用任何个数据之前加载所有数据,而不是在使用第一个需要它的类型时加载?

    我不相信有任何方法可以从程序集中强制在程序集负载上运行方法。您可以在 every 类型中放置一个静态构造函数,但坦率地说,我认为拥有一个表示该数据并提供对它的访问的单一类型更有意义 - 并且仅在该类型上放置一个静态构造函数。 (如果您有可以独立使用的单独数据位,也许可以为它们创建单独的类型。)

    【讨论】:

    • 我没有提到加载任何数据。我真的只是想确保该库使用特定的 DateTime 转换器而不是默认转换器。 (见stackoverflow.com/questions/458935/extend-a-typeconverter)。
    • 所以我只想在加载程序集时运行一次此代码:TypeDescriptor.AddAttributes(typeof(DateTime), new TypeConverterAttribute(typeof(DateTimeConverterEx)));
    • 所以在每个使用转换器的类型中放置一个静态构造函数。很不幸,但这就是静态要付出的代价:(
    • 实际上可能希望在程序集加载时运行代码 - 例如,如果涉及昂贵的初始化,最好在一个地方解决。当然,可以通过在程序集中手动查找一些初始化例程并执行它来解决这个问题,但是框架是否提供了用于执行此操作的内置方法的问题确实有它的位置。
    • @JonSkeet "为什么在使用任何数据之前都需要加载所有数据?"假设有某个类型为Vector3 的第3 方库。还有一个带有操作注册表的库,您可以在其中注册任何类型的操作(例如,添加或转换)。现在有一个几何库可以实现和使用矢量运算。几何库想要在操作注册表中注册向量操作。此初始化应在程序集加载时执行。这是可能的 - 只需向 <Module> 类添加一个静态构造函数。
    【解决方案2】:

    只有当您可以控制主执行程序集时,以下解决方案才可能,即它不适合用于分发的独立库

    我遇到了类似的问题,并通过使用 Type 参数创建面向程序集的属性“InitializeOnLoad”来解决它。然后,在主可执行文件中,我添加了一个简单的 AppDomain.AssemblyLoaded 处理程序,它会扫描新加载的程序集以查找上述属性并调用 System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor()。

    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
    public class InitializeOnLoadAttribute : Attribute
    {
        Type type;
    
        public InitializeOnLoadAttribute(Type type) { this.type = type; }
    
        public Type Type { get { return type; } }
    }
    
    // somewhere very early in main exe initialization
    AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(AssemblyInitializer);
    
    static void AssemblyInitializer(object sender, AssemblyLoadEventArgs args)
    {
        // force static constructors in types specified by InitializeOnLoad
        foreach (InitializeOnLoadAttribute attr in args.LoadedAssembly.GetCustomAttributes(typeof(InitializeOnLoadAttribute), false))
            System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(attr.Type.TypeHandle);
    }
    

    此外,如果您担心在您挂钩 AssemblyLoad 事件之前可能已经加载了程序集,您可以简单地运行 AppDomain.GetAssemblies() 并为它们调用“初始化程序”。

    【讨论】:

      【解决方案3】:

      是的,有——有点。

      使用 Einar Egilsson 的优秀小工具,InjectModuleInitializer

      将此可执行文件作为构建后步骤运行,以创建一个小的 .cctor 函数(模块初始化函数),该函数调用您的不带参数的静态 void 函数。如果编译器给了我们创建 .cctor() 的能力就好了,幸运的是我们很少需要这个能力。

      然而,这并不是一个完整的 DllMain 替代品。 CLR 仅在程序集中调用任何方法之前调用此 .cctor 函数,而不是在程序集加载时调用。因此,如果您需要在程序集加载时发生某些事情,您需要让加载代码直接调用一个方法或使用我详述的 hack https://stackoverflow.com/a/9745422/240845

      【讨论】:

        【解决方案4】:

        这是可能的 - 只需将静态构造函数添加到 <Module> 类。不过,我不知道如何在不修改 IL 的情况下完成此操作。

        【讨论】:

        • 福迪。只需安装-Package ModuleInit.Fody
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多