C# 如何从主 AppDomain 卸载程序集?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/123391/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 14:37:43  来源:igfitidea点击:

How to unload an assembly from the primary AppDomain?

提问by Derik Whittaker

I would like to know how to unload an assembly that is loaded into the main AppDomain.

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

I have the following code:

我有以下代码:

var assembly = Assembly.LoadFrom( FilePathHere );

I need/want to be able to unload this assembly when I am done.

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

Thanks for your help.

谢谢你的帮助。

回答by Philip Rieck

For .net versions core 3.0 and later:

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

You can now unload assemblies. Note that appdomains are no longer available in .net core. Instead, you can create one or more AssemblyLoadContext, load your assemblies via that context, then unload that context. See AssemblyLoadContext, or this tutorial that simulates loading a plugin then unloading it.

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

For .net versions before .net core 3, including netframework 4 and lower

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

You can not unload an assembly from an appdomain. You can destroy appdomains, but once an assembly is loaded into an appdomain, it's there for the life of the appdomain.

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

See Jason Zander's explanation of Why isn't there an Assembly.Unload method?

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

If you are using 3.5, you can use the AddIn Framework to make it easier to manage/call into different AppDomains (which you canunload, unloading all the assemblies). If you are using versions before that, you need to create a new appdomain yourself to unload it.

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

回答by Mark Cidade

You can't unload an assembly without unloading the whole AppDomain. Here's why:

您不能在不卸载整个 AppDomain 的情况下卸载程序集。原因如下:

  1. You are running that code in the app domain. That means there are potentially call sites and call stacks with addresses in them that are expecting to keep working.

  2. Say you did manage to track all handles and references to already running code by an assembly. Assuming you didn't ngen the code, once you successfully freed up the assembly, you have only freed up the metadata and IL. The JIT'd code is still allocated in the app domain loader heap (JIT'd methods are allocated sequentially in a buffer in the order in which they are called).

  3. The final issue relates to code which has been loaded shared, otherwise more formally know as "domain neutral" (check out /shared on the ngen tool). In this mode, the code for an assembly is generated to be executed from any app domain (nothing hard wired).

It is recommended that you design your application around the application domain boundary naturally, where unload is fully supported.

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

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

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

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

回答by Khoth

If you want to have temporary code which can be unloaded afterwards, depending on your needs the DynamicMethodclass might do what you want. That doesn't give you classes, though.

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

回答by Nipun

You should load your temporary assemblies in another AppDomainand when not in use then you can unload that AppDomain. It's safe and fast.

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

回答by GenZiy

Here is a GOOD example how to compile and run dll during run time and then unload all resources: http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm

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

回答by Bruno Pires Lavigne Quintanilh

I know its old but might help someone. You can load the file from stream and release it. It worked for me. I found the solution HERE.

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

Hope it helps.

希望能帮助到你。

回答by Kirk Herron

I also know this is very old, but may help someone who is having this issue! Here is one way I have found to do it! instead of using:

我也知道这很旧,但可能会帮助遇到此问题的人!这是我找到的一种方法!而不是使用:

var assembly = Assembly.LoadFrom( FilePathHere );

use this:

用这个:

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

This actually loads the "Contents" of the assembly file, instead of the file itself. Which means there is NOT a file lock placed on the assembly file! So now it can be copied over, deleted or upgraded without closing your application or trying to use a separate AppDomain or Marshaling!

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

PROS:Very Simple to fix with a 1 Liner of code! CONS:Cannot use AppDomain, Assembly.Location or Assembly.CodeBase.

优点:用 1 行代码修复非常简单! 缺点:不能使用 AppDomain、Assembly.Location 或 Assembly.CodeBase。

Now you just need to destroy any instances created on the assembly. For example:

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

assembly = null;

回答by Gerrie Pretorius

As an alternative, if the assembly was just loaded in the first place, to check information of the assembly like the publicKey, the better way would be to not load it,and rather check the information by loading just the AssemblyName at first:

作为替代方案,如果程序集刚开始被加载,为了检查像 publicKey 这样的程序集信息,更好的方法是不加载它,而是首先通过加载 AssemblyName 来检查信息:

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

EDIT

编辑

If you need to reflect the types in the assembly without getting the assembly in to your app domain, you can use the Assembly.ReflectionOnlyLoadFrommethod. this will allow you to look at they types in the assembly but not allow you to instantiate them, and will also not load the assembly in to the AppDomain.

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

Look at this example as exlanation

看这个例子作为解释

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
}