为什么我需要AssemblyResolve处理程序来处理已经加载的程序集?

时间:2013-11-26 02:54:09

标签: c# .net reflection system.reflection

我有两个程序集:AppAddOnApp引用AddOn,但CopyLocal设置为false,因为AddOnApp动态加载。

以下是AddOn中的代码:

namespace AddOn
{
    public class AddOnClass
    {
        public static void DoAddOnStuff()
        {
            Console.WriteLine("AddOn is doing stuff.");
        }
    }
}

以下是App中的代码:

class Program
{
    static void Main(string[] args)
    {
        Assembly.LoadFrom(@"..\..\..\AddOn\bin\Debug\AddOn.dll");

        // Without this event handler, we get a FileNotFoundException.
        // AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
        // {
        //     return AppDomain.CurrentDomain.GetAssemblies()
        //                     .FirstOrDefault(a => a.FullName == e.Name);
        //};

        CallAddOn();
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    private static void CallAddOn()
    {
        AddOnClass.DoAddOnStuff();
    }
}

我不明白为什么代码不能与AssemblyResolve中评论的Main()处理程序一起使用。在Visual Studio中运行时,调试器会在CallAddOn()上使用FileNotFoundException中断。为什么抱怨?程序集已加载,它与App引用的版本完全相同(即磁盘上的文件相同)。

我觉得有一些基本概念,我在这里不能正确理解。评论AssemblyResolve处理程序工作正常,但它似乎是一个黑客,我不明白为什么我需要它,因为它似乎做了一些微不足道的事情。

1 个答案:

答案 0 :(得分:9)

原因是有多个程序集加载上下文。加载程序集的上下文会影响它的使用方式。当运行时使用默认探测机制加载程序集时,它将被置于所谓的Load上下文中。这是通过Assembly.Load加载程序集时使用的上下文。您已使用LoadFrom加载程序集,LoadFrom使用自己的上下文。探测不会检查LoadFrom上下文,并且文件不在探测路径中,因此您需要为运行时解析它。然而,这不是对称的。如果在Load上下文中加载了程序集,ReflectionOnlyLoad将首先从那里加载它(假设标识是相同的。对于无符号程序集,路径是标识的一部分。)。我会注意到有更多的上下文,包括ReflectionOnlyLoadFromLoadFileprivatePath加载没有上下文的程序集,即必须手动加载所有依赖项。

如果希望在Load上下文中解析程序集,但是它们存在于应用程序的默认探测路径之外,您也可以通过配置来执行它。使用程序集绑定重定向的<codebase>元素或<probing>元素的{{1}}属性。

阅读this了解详情。 Suzanne Cook还提供了一些博客文章,其中包括装配加载和上下文(请参阅hereherehere)。