使用AppDomain.AssemblyResolve事件

dav*_*ooh 11 .net c# .net-assembly

我正在尝试使用AppDomain.AssemblyResolve事件来处理异常,同时解析在运行时加载的某些DLL的程序集(SerializedException用于动态加载的Type).

当事件被触发时,我在我的目录中加载所有DLL并创建一个Assembly数组,然后我使用此方法来获取Assembly包含我指定的类型:

public static Assembly GetAssemblyContainingType(String completeTypeName, 
                                                 Assembly[] assemblies)
{
    Assembly assembly = null;

    foreach (Assembly currentassembly in assemblies)
    {
        Type t = currentassembly.GetType(completeTypeName, false, true);
        if (t != null)
        {
            assembly = currentassembly;
            break;
        }
    }

    return assembly;
}
Run Code Online (Sandbox Code Playgroud)

问题是这个代码只能用于一个AssemblyQualifiedName,并且ResolveEventArgs.Name事件提供的代码不是那么有用.

你能建议我一些解决方法吗?

有没有办法在事件被触发时传递一些其他参数?

das*_*ght 17

您可以从目录中定义程序集的字典,如下所示:

private readonly IDictionary<string,Assembly> additional =
    new Dictionary<string,Assembly>();
Run Code Online (Sandbox Code Playgroud)

使用已知目录中的程序集加载此字典,如下所示:

foreach ( var assemblyName ... corresponding to DLL names in your directory... ) {
    var assembly = Assembly.Load(assemblyName);
    additional.Add(assembly.FullName, assembly);
}
Run Code Online (Sandbox Code Playgroud)

提供钩子的实现......

private Assembly ResolveAssembly(Object sender, ResolveEventArgs e) {
    Assembly res;
    additional.TryGetValue(e.Name, out res);
    return res;
}
Run Code Online (Sandbox Code Playgroud)

...并将其连接到事件:

AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += ResolveAssembly;
AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
Run Code Online (Sandbox Code Playgroud)

这应该可以解决问题.

  • 在构建字典时,使用AssemblyName.GetAssemblyName(<assemblyFile>)而不是Assmebly.Load来获取文件名映射的程序集名称,并避免无条件地加载所有程序集. (6认同)
  • 不预加载程序集是否不需要AssemblyResolve事件处理程序? (5认同)
  • @mikez据我所知,只需使用`Assembly.Load(assemblyName)`加载程序集不会自动使其可用于应用程序域的程序集解析代码(除非该代码可以使用默认的解析进程访问程序集).这个代码是从一个工作系统中解放出来的(我删除了错误处理代码,例如`additional.TryGetValue(e.Name,out res)`调用以简化一些事情).当我删除`ResolveAssembly`钩子时,我的工作系统停止工作:) (3认同)