加载字节数组装配

sir*_*lot 7 c# appdomain

我正在尝试使用字节数组加载程序集,但我无法弄清楚如何让它正常工作.这是设置:

public static void Main() 
{
    PermissionSet permissions = new PermissionSet(PermissionState.None);
    AppDomainSetup setup = new AppDomainSetup { ApplicationBase = Environment.CurrentDirectory };
    AppDomain friendlyDomain = AppDomain.CreateDomain("Friendly", null, setup, permissions);

    Byte[] primary = File.ReadAllBytes("Primary.dll_");
    Byte[] dependency = File.ReadAllBytes("Dependency.dll_");

    // Crashes here saying it can't find the file.
    friendlyDomain.Load(dependency);

    AppDomain.Unload(friendlyDomain);

    Console.WriteLine("Stand successful");
    Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)

我创建了两个模拟dll,并故意将其扩展名重命名为".dll_",因此系统无法找到物理文件.双方primarydependency正确填写,但是当我试图调用AppDomain.Load与二进制数据的方法,它回来:

Could not load file or assembly 'Dependency, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

为什么要在系统中搜索文件?

UPDATE

另一方面,这似乎工作:

public class Program {
    public static void Main() {
        PermissionSet permissions = new PermissionSet(PermissionState.Unrestricted);
        AppDomainSetup setup = new AppDomainSetup { ApplicationBase = Environment.CurrentDirectory };
        AppDomain friendlyDomain = AppDomain.CreateDomain("Friendly", null, setup, permissions);

        Byte[] primary = File.ReadAllBytes("Primary.dll_");
        Byte[] dependency = File.ReadAllBytes("Dependency.dll_");

        // Crashes here saying it can't find the file.
        // friendlyDomain.Load(primary);

        Stage stage = (Stage)friendlyDomain.CreateInstanceAndUnwrap(typeof(Stage).Assembly.FullName, typeof(Stage).FullName);
        stage.LoadAssembly(dependency);

        Console.WriteLine("Stand successful");
        Console.ReadLine();
    }

}

public class Stage : MarshalByRefObject {
    public void LoadAssembly(Byte[] data) {
        Assembly.Load(data);
    }
}
Run Code Online (Sandbox Code Playgroud)

所以看起来AppDomain.Load和之间存在差异Assembly.Load.

Han*_*ant 10

这是正常的,CLR在搜索"主要"需要的程序集时不会将您加载的"依赖项"视为合适的程序集.与"加载上下文"相关的问题,没有一个像这样加载的程序集.这是故意的,CLR无法确保DLL Hell不会成为问题,因为它不知道程序集的来源.既然你打开了DLL Hell的大门,你也必须自己避开地狱.

您需要实现AppDomain.AssemblyResolve事件.它会在CLR找不到"依赖"时触发,你可以返回从Assembly.Load(byte [])获得的程序集.但是,当它为同一个程序集触发不止一次时,你必须这样做,换句话说,返回完全相同的程序集,否则你会遇到更多由.NET类型标识引起的问题.产生难以理解的铸造异常,"无法铸造Foo to Foo"的风格.

还有其他问题,效率很低.程序集的虚拟内存不能由磁盘上的文件支持,因此它由页面文件支持.这会增加进程的提交大小.

不这样做当然更好.


Pan*_*nis 5

这两种方法之间没有区别(您可以根据需要检查官方源代码)。

AppDomain.Load方法(Byte [])的MSDN页面中,注意到该方法正在当前应用程序域中加载程序集:

此方法仅应用于将程序集加载到当前应用程序域中。此方法为无法调用静态Assembly.Load方法的互操作性调用者提供了便利。要将程序集加载到其他应用程序域中,请使用诸如CreateInstanceAndUnwrap之类的方法。

该行:

friendlyDomain.Load(dependency);
Run Code Online (Sandbox Code Playgroud)

与以下行为完全相同:

Assembly.Load(dependency);
Run Code Online (Sandbox Code Playgroud)

它在更新的示例代码中起作用的原因是,该Stage对象实际上是Assembly.Load AppDomain 内部调用的。

注意:此答案是对Hans Passant和colinsmith的回答的补充。