有一个事件AppDomain.CurrentDomain.DomainUnload
,它允许清理独立于任何特定类实例甚至任何特定类的静态资源。
我认为它是在我当前程序集中的任何代码之后执行的代码(顺便说一句,我是不是?)。
但是有没有办法编写一段代码(对于当前程序集),它将在当前程序集(类库)中的任何其他代码之前执行?或者我应该在任何代码开始执行之前寻找一种更棘手的方法来初始化某些资源吗?
我知道静态构造函数,但是它们的调用顺序没有明确定义。换句话说,不能保证在其他类的其他静态构造函数之前执行特定的静态构造函数。
还有AppDomain.AssemblyLoad
。我不确定这是我要找的东西。加载OTHER程序集时会发生此事件,而不是当前程序。
答案 0 :(得分:2)
我有同样的问题并以这种方式解决了。
我只使用方法IAssembyInitializer
定义void Initialize()
接口。
在我想要在加载之后执行某些代码的每个程序集中,我定义了一个实现此接口的类。
我定义了一个属性来指定实现这个接口的程序集中的类(否则你可以通过Reflection找到它们,但我更喜欢这样):
[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();
}
}
}
答案 1 :(得分:1)
您可以使用静态字段中保存的Lazy<T>
实例来自行控制静态初始化顺序。这些Lazy<T>
初始化程序对象的代码体可以引用其他Lazy<T>
实例,这些实例会自动编排初始化的DAG。显然你不能有周期。
使用C ++ / CLI,您确实可以在程序集加载时执行代码(模块初始化程序)。你可能不想走那条路。
使用C#,这是不可能的。静态缓存和懒惰的初始化模式是你得到的最好的。
答案 2 :(得分:0)
您可能希望扫描代码并找到需要完成初始化的地方。
然后在初始化尚未运行时启动初始化。
在.NET中,您根本不知道何时会加载程序集,因此没有保证初始化将在所有方案中及时启动。
另一种方法是让程序集的客户端通过调用方法显式启动初始化。 (如果尚未加载,那也会加载程序集)
可以像在客户端中那样使用AssemblyLoad事件来检测特定程序集的加载,但这将使初始化依赖于客户端实现,而第一个解决方案将此责任保留在程序集本身的范围内。
答案 3 :(得分:0)
假设您无法控制如何使用类库,您可以为库中的每个公共/受保护类编写静态构造函数,并从每个类中调用初始化代码。显然,初始化代码必须跟踪第一次调用(通过静态字段),以便它只运行一次。
答案 4 :(得分:-1)
您可以使用Module Initializers执行此操作。它们不是直接支持在C#中,但如果您不反对使用Cecil发布处理程序集,则可以使用它们。