C# 在程序集加载时初始化库

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/459560/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 04:13:38  来源:igfitidea点击:

Initialize library on Assembly load

c#.netassemblies

提问by sixtowns

I have a .net library dll that acts like a functional library. There are a bunch of static types along with static methods.

我有一个 .net 库 dll,它就像一个函数库。有一堆静态类型和静态方法。

There is some initialization code that I need to run to set up the library ready for use.

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

When the assembly gets loaded is there a way to ensure that a particular method is run? Something like AppDomain.AssemblyLoad but called automatically from the assembly itself. I was thinking that maybe there is something like an AssemblyAttribute that could be used?

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

At the moment I have this initialization code in a static constructor but as this is a library with many entry points there is no guarantee that this particular type will be used.

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

Thanks!

谢谢!

采纳答案by Jon Skeet

Why do you need all the data to be loaded before anyof it is used, rather than just when the first type which needs it is used?

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

I don't believe there's any way of forcing a method to be run on assembly load, from within the assembly. You could put a static constructor in everytype, but frankly I think it just makes more sense to have a single type representing that data and providing access to it - and put a static constructor on that type alone. (If you've got separate bits of data which can be used independently, perhaps create separate types for them.)

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

回答by Stefan Simek

The following solution is possible only when you have control over the main executing assembly, i.e. it's not suitable for standalone libraries meant for distribution

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

I've had a similar problem and solved it by creating an assembly-targeted attribute 'InitializeOnLoad' with a Type parameter. Then, in the main executable, I've added a trivial AppDomain.AssemblyLoaded handler, which scans the newly loaded assembly for the aforementioned attribute and calls System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor() on them.

我遇到了类似的问题,并通过使用 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);
}

additionaly, if you are afraid that assemblies might have been loade before you hook the AssemblyLoad event, you can simply run through AppDomain.GetAssemblies() and call the 'initializer' for them.

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

回答by mheyman

Yes there is - sort of.

是的,有 - 有点。

Use the excellent little utility by by Einar Egilsson, InjectModuleInitializer.

使用 Einar Egilsson 的优秀小实用程序InjectModuleInitializer

Run this executable as a post build step to create a small .cctor function (the module initializer function) that calls a static void function of yours that takes no parameters. It would be nice if compiler gave us the ability to create .cctor(), luckily we rarely need this capability.

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

This is not a complete DllMain replacement, however. The CLR only calls this .cctor function prior to any methods called in your assembly, not upon assembly load. So, if you need something to happen upon assembly load, you need to have the loading code call a method directly or use the hack I detailed https://stackoverflow.com/a/9745422/240845

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

回答by Ark-kun

It's possible - just add a static constructor to the <Module>class. I don't know how to accomplish this without IL modification though.

这是可能的 - 只需向<Module>类添加一个静态构造函数。我不知道如何在没有 IL 修改的情况下实现这一点。