处理AppDomain.AssemblyResolve事件

12

我尝试使用AppDomain.AssemblyResolve事件来处理运行时加载的某些dll程序集解析异常(动态加载类型的SerializationException)。

当该事件被触发时,我会加载目录中的所有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;
}

问题在于这段代码只能使用AssemblyQualifiedName,而事件提供的ResolveEventArgs.Name并不是很有用。

你能否提出一些解决方法?

在触发事件时,是否有办法传递其他参数?

2个回答

19
你可以定义一个包含你目录中程序集信息的字典,如下所示:
private readonly IDictionary<string,Assembly> additional =
    new Dictionary<string,Assembly>();

从已知目录加载程序集到该字典中,可以按照以下方式进行:

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

为挂钩提供一个实现...

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

...然后将其连接到事件:

AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += ResolveAssembly;
AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;

这应该能解决问题。


5
预加载程序集不是让AssemblyResolve事件处理程序变得无关紧要吗? - Mike Zboray
4
据我所知,仅使用 Assembly.Load(assemblyName) 加载程序集并不会自动使其可用于应用程序域的程序集解析代码(除非该代码可以使用默认的解析过程访问该程序集)。此代码来自一个工作系统(我删除了错误处理代码,例如在 additional.TryGetValue(e.Name, out res) 调用周围的代码,以简化代码)。当我移除 ResolveAssembly 钩子时,我的工作系统就停止工作了 :) - Sergey Kalinichenko
8
在构建字典时,使用AssemblyName.GetAssemblyName(<assemblyFile>)获取程序集名称到文件名的映射,避免无条件加载所有程序集。不要使用Assmebly.Load。 - Simon Brangwin

0

如果您知道可能包含您计划反序列化的类型的程序集列表,最好在执行序列化之前预加载所有程序集。

当触发AssemblyResolve事件时,您没有关于导致加载的类型的信息,只有程序集名称。在这种情况下,不清楚为什么要按某个特定类型查找程序集。

请注意,如果两个程序集恰好具有相同的标识(即非强名称文件名),并且已经加载了一个程序集,则即使在已加载的程序集中未找到类型,事件也不会在您期望的时间触发。

历史目的链接文章:解决程序集加载问题


正如你在我的旧问题(http://stackoverflow.com/q/9158353/1061499)中所读到的一样,我正在开发一个应用程序,使用插件方法在运行时加载界面的各种应用程序。当应用程序关闭时,我需要序列化这些对象,然后在应用程序重新启动时,这些对象必须被反序列化。问题是对象类型在运行时加载,所以它们的类型无法解析... - davioooh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接