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

Rob*_*los 10 .net c# reflection system.reflection

我有两个组件:AppAddOn. App引用AddOn,但CopyLocal设置为false,因为AddOn将动态加载App.

这是以下代码AddOn:

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

这里的代码是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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Mik*_*ray 9

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

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

阅读本文以获取更多信息.苏珊娜·库克(Suzanne Cook)也有一些博客文章从一段时间后回到装配加载和上下文(见这里,这里这里).