50

我想知道如何卸载加载到主 AppDomain 中的程序集。

我有以下代码:

var assembly = Assembly.LoadFrom( FilePathHere );

完成后,我需要/希望能够卸载此程序集。

谢谢你的帮助。

4

8 回答 8

42

对于 .net 版本的 core 3.0 及更高版本:

您现在可以卸载程序集。请注意,应用程序域在 .net 核心中不再可用。相反,您可以创建一个或多个 AssemblyLoadContext,通过该上下文加载程序集,然后卸载该上下文。请参阅AssemblyLoadContext模拟加载插件然后卸载它的本教程

对于 .net core 3 之前的 .net 版本,包括网络 4 及更低版本

您不能从 appdomain 中卸载程序集。您可以销毁应用程序域,但是一旦程序集加载到应用程序域中,它就会在应用程序域的整个生命周期内一直存在。

请参阅 Jason Zander 对为什么没有 Assembly.Unload 方法的解释?

如果您使用的是 3.5,则可以使用 AddIn Framework 来更轻松地管理/调用不同的 AppDomain(您可以卸载它们,卸载所有程序集)。如果您使用的是之前的版本,您需要自己创建一个新的 appdomain 来卸载它。

于 2008-09-23T19:51:53.083 回答
28

我也知道这已经很老了,但可以帮助遇到这个问题的人!这是我发现的一种方法!而不是使用:

var assembly = Assembly.LoadFrom( FilePathHere );

用这个:

var assembly = Assembly.Load( File.ReadAllBytes(FilePathHere));

这实际上加载了程序集文件的“内容”,而不是文件本身。这意味着程序集文件上没有文件锁!所以现在它可以被复制、删除或升级,而无需关闭您的应用程序或尝试使用单独的 AppDomain 或编组!

优点:很容易用 1 行代码修复! 缺点:不能使用 AppDomain、Assembly.Location 或 Assembly.CodeBase。

现在您只需要销毁在程序集上创建的任何实例。例如:

assembly = null;
于 2015-12-03T22:03:17.130 回答
16

如果不卸载整个 AppDomain,就无法卸载程序集。原因如下:

  1. 您正在应用程序域中运行该代码。这意味着潜在的调用站点和调用堆栈中的地址有望继续工作。

  2. 假设您确实设法跟踪程序集对已运行代码的所有句柄和引用。假设你没有生成代码,一旦你成功释放了程序集,你只释放了元数据和 IL。JIT 代码仍然分配在应用程序域加载器堆中(JIT 方法按调用顺序在缓冲区中顺序分配)。

  3. 最后一个问题与已加载共享的代码有关,否则更正式地称为“域中立”(在 ngen 工具上查看 /shared)。在这种模式下,生成的程序集代码可以从任何应用程序域执行(没有硬连线)。

建议您围绕应用程序域边界自然地设计应用程序,完全支持卸载。

于 2008-09-23T19:52:34.487 回答
11

您应该在另一个中加载您的临时程序集AppDomain,当不使用时,您可以卸载它AppDomain。它安全快捷。

于 2009-03-20T14:12:22.283 回答
5

如果您想拥有可以在之后卸载的临时代码,则根据您的需要,DynamicMethod该类可能会执行您想要的操作。不过,这并没有给你上课。

于 2008-09-23T19:59:38.883 回答
1

我知道它很旧,但可能会帮助某人。您可以从流中加载文件并释放它。它对我有用。我在这里找到了解决方案。

希望能帮助到你。

于 2014-11-28T15:05:36.043 回答
1

这是一个很好的例子,如何在运行时编译和运行 dll,然后卸载所有资源: http ://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm

于 2009-12-24T14:45:53.100 回答
0

作为替代方案,如果程序集刚刚加载,要检查公共密钥等程序集的信息,更好的方法是不加载它,而是首先仅加载 AssemblyName 来检查信息:

AssemblyName an = AssemblyName.GetAssemblyName ("myfile.exe");
byte[] publicKey = an.GetPublicKey();
CultureInfo culture = an.CultureInfo;
Version version = an.Version;

编辑

如果您需要在程序集中反映类型而不将程序集放入您的应用程序域,您可以使用该Assembly.ReflectionOnlyLoadFrom方法。这将允许您查看它们在程序集中的类型,但不允许您实例化它们,并且也不会将程序集加载到 AppDomain。

看这个例子作为解释

public void AssemblyLoadTest(string assemblyToLoad)
{
    var initialAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4

    Assembly.ReflectionOnlyLoad(assemblyToLoad);
    var reflectionOnlyAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4

    //Shows that assembly is NOT loaded in to AppDomain with Assembly.ReflectionOnlyLoad
    Assert.AreEqual(initialAppDomainAssemblyCount, reflectionOnlyAppDomainAssemblyCount); // 4 == 4

    Assembly.Load(assemblyToLoad);
    var loadAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //5

    //Shows that assembly is loaded in to AppDomain with Assembly.Load
    Assert.AreNotEqual(initialAppDomainAssemblyCount, loadAppDomainAssemblyCount); // 4 != 5
}
于 2018-03-07T15:07:21.753 回答