如何在不使用Assembly.Load的情况下加载程序集?

Joa*_*nge 5 .net c# reflection assemblies

是否可以通过将程序集流式传输到内存中来实现此目的?如果是这样,那怎么做呢?

原因:

我不想锁定加载的DLL.我希望能够动态加载,更改代码,再次编译和重新加载它

ang*_*son 19

据我了解,您想要执行以下操作:

  1. 将程序集从磁盘加载到内存中,以便使用其中的数据或调用其中的代码
  2. 以后能够卸载组件
  3. 避免将组件锁定在磁盘上,以便您可以修改它而无需退出应用程序(或首先卸载组件)

基本上,您所描述的是各种插件系统,您可以使用阴影dll和应用程序域来实现.

首先,为了卸载程序集,不需要退出应用程序,您需要将该程序集加载到单独的应用程序域中.你应该能够在网上找到关于如何做到这一点的好教程.

这是一个谷歌查询,应该为您提供一些起始文章.

其次,为了避免将程序集锁定在磁盘上,这很简单,只需先复制它,然后加载副本而不是原始副本.当然,你将锁定副本,但副本只是你的应用程序的临时文件,所以没有人应该有兴趣修改该文件.这使原始文件解锁并可修改.

Assembly.Load如果您有多个将要加载和替换的程序集,您应该尝试使用阴影而不是使用可以从字节数组加载程序集的重载.

例如,如果您的插件程序集A.dll依赖于第二个程序集B.dll,并且在调用Assembly.Load之前使用字节数组技巧将A.dll加载到内存中,则需要在应用程序中处理程序集解析调用domain(你可以在需要加载程序集时告诉你,并且"帮助"加载过程),或者你需要确保B.dll首先以加载A.dll的方式加载,否则从中加载A.dll内存将自动从磁盘加载B.dll.


以下是有关使用单独的应用程序域的更多信息.

当您创建另一个应用程序域时,通过在.NET中使用AppDomain类,您将在内存中创建一个单独的隔离专区,您可以在其中运行代码.它实际上与您的主应用程序域分开,并且只有一个穿过隔离墙的小孔.

通过这个洞,您可以传递消息,如方法调用和数据.

构建新的应用程序域后,在其中加载一个或多个程序集.通常,如果要为此类加载构建要加载到其中的程序集,则将加载1;如果尚未加载,则加载2(下面将详细介绍).

加载程序集后,在另一个应用程序域中构造一个或多个对象,使第一个应用程序域可以与这些对象进行通信.这些对象需要从MarshalByRefObject继承,MarshalByRefObject是一个允许发生魔法的类.

基本上会发生这种情况.在其他应用程序域内,创建了加载到该应用程序域中的类型的对象.此类型来自MarshalByRefObject.构造此对象的请求来自第一个应用程序域,并且在此应用程序域内部构造了一个代理对象,该对象看起来像是在同一个应用程序域中创建的相同对象.代理通过那个洞与另一个对象交谈.

所以现在你有两个应用程序域,两个对象,每边一个,并且对象相互通信.

通过此设置,稍后您可以切断对象之间的连接,然后卸载其他应用程序域,这基本上会拆除该隔离专区.然后,如果您愿意,可以构建一个新的第二个应用程序域,并重新开始,实际上再次从磁盘重新加载程序集.

需要注意的一件事是你通过这个洞的数据.如果您通过该孔传递的任何数据是在您加载的程序集(您的插件或扩展程序集)中声明的对象,那么您不仅会将该对象返回到您的主应用程序域,您的主应用程序域也将将该程序集加载到其自己的域中,从而使重新加载后无法正确地与第二个应用程序域通信.

因此,请确保不要这样做,传递本机类型或在要替换的程序集之外定义的类型.

我提到你可能想要加载至少两个程序集.这背后的原因是,如果你想构造一个对象的类型,你要加载的那个程序集中声明的类型,不会从MarshalByRefObject下降,那么再次通过那个洞传递类型的问题就会出现,并且您也可以将程序集加载到主域中.处理此问题的一种典型方法是使用某种插件管理器类,它确实来自MarshalByRefObject,并让此管理器位于其他域中并与其他类型进行通信.这避免了通过该洞传递类型的问题.

我已经在这里漫游了一段时间,所以我会留下它,但是通过这些信息,您应该能够理解并利用通过Google查询找到的文章更容易一些.


Eli*_*sha 11

它可以通过使用字节数组的Load重载来完成.您需要在加载之前读取汇编字节,它不会锁定文件:

byte[] readAllBytes = File.ReadAllBytes("path");
Assembly assembly = Assembly.Load(readAllBytes);
Run Code Online (Sandbox Code Playgroud)

  • 从字节加载时,每次都会加载一个副本.您将获得一个可以工作的新程序集引用,但它不会卸载旧程序集.这取决于你实际上要做什么,所以这是一个简单的权衡. (3认同)