如何编写要在程序集中的任何方法之前执行的代码

本文关键字:方法 任何 代码 执行 集中 何编写 程序 程序集 | 更新日期: 2023-09-27 17:55:51

有一个事件AppDomain.CurrentDomain.DomainUnload允许清理独立于任何特定类实例甚至任何特定类的静态资源。我认为它是在当前程序集中的任何代码之后执行的代码(顺便说一下,我是对的吗?

但是有没有办法编写一段代码(对于当前程序集),该代码要在当前程序集(类库)中的任何其他代码之前执行?还是我应该在任何代码开始执行之前寻找一种更棘手的方法来初始化一些资源?

我知道静态构造函数,但它们的调用顺序没有很好地定义。换句话说,不能保证特定的静态构造函数将先于其他类的其他静态构造函数执行。

还有一个AppDomain.AssemblyLoad。 我不确定这是我正在寻找的东西。加载 OTHER 程序集(而不是当前程序集)时,会发生此事件。

如何编写要在程序集中的任何方法之前执行的代码

我遇到了同样的问题,并以这种方式解决了它。我只用方法void Initialize()定义了一个IAssembyInitializer接口。在我想在加载代码后立即执行某些代码的每个程序集中,我定义了一个实现此接口的类。I 定义一个属性来指定实现此接口的程序集中的类(否则您可以通过反射找到它们,但我更喜欢这种方式):

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class AssemblyInitializerAttribute : Attribute
{
    AssemblyInitializerAttribute ()
    {
    }
    AssemblyInitializerAttribute (string typeName)
    {
        TypeName = typeName;
    }
    public string TypeName;
}

该属性在AssemblyInfo中按以下方式设置:

[assembly: AssemblyInitializerAttribute ("MyNamespace.AnAssemblyInitializer")]

最后,在应用程序的主程序集中,我向 AssemblyLoad 事件注册了一个执行所有初始化的方法:

AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(NewAssemblyLoaded);
        static void NewAssemblyLoaded(object sender, AssemblyLoadEventArgs args)
        {
            Assembly anAssembly = args.LoadedAssembly;
            AssemblyInitializerAttribute[] initializers = (AssemblyInitializerAttribute[])anAssembly .GetCustomAttributes(typeof(AssemblyInitializerAttribute), false);
            foreach (AssemblyInitializerAttribute anInit in initializers)
            {
                Type initType = anInit.TypeName != null ? anAssembly.GetType(anInit.TypeName) : null;
                if (initType != null && initType.GetInterface("IAssemblyInitializer") != null)
                {
                    IAssemblyInitializer anInitializer = (IAssemblyInitializer)Activator.CreateInstance(initType);
                    anInitializer.Initialize();
                }
            }
        }

您可以使用静态字段中保存的Lazy<T>实例来控制静态初始化顺序。这些Lazy<T>初始值设定项对象的代码正文可以引用其他 Lazy<T> 实例,这些实例会自动编排初始化的 DAG。显然,你不能有周期。

使用 C++/CLI,您确实可以在程序集加载时执行代码(模块初始值设定项)。你可能不想走那条路。

使用 C# 时,这是不可能的。静态 ctor 和延迟初始化模式是最好的。

您可能希望扫描代码并找到需要完成初始化的位置。

然后在初始化尚未运行时,在需要初始化之前启动初始化。

在 .NET 中,您根本不知道何时加载程序集,因此无法保证初始化将在所有情况下及时启动。

另一种方法是程序集的客户端通过调用方法显式启动初始化。(如果尚未加载程序集,这也将加载程序集)

AssemblyLoad 事件可以像在客户端中一样用于检测特定程序集的加载,但这将使初始化依赖于客户端实现,而第一个解决方案将此责任保留在程序集本身的范围内。

假设您无法控制类库的使用方式,则可以为库中的每个公共/受保护类编写静态构造函数,并从每个类调用初始化代码。显然,初始化代码必须跟踪第一次调用(通过静态字段),以便它只运行一次。

您可以使用模块初始值设定项执行此操作。 它们在 C# 中不直接受支持,但如果你不反对使用 Cecil 对程序集进行后处理,则可以使用它们。