C# 如何从主AppDomain卸载程序集?
我想知道如何卸载加载到主AppDomain中的程序集 我有以下代码:C# 如何从主AppDomain卸载程序集?,c#,.net,appdomain,C#,.net,Appdomain,我想知道如何卸载加载到主AppDomain中的程序集 我有以下代码: var assembly = Assembly.LoadFrom( FilePathHere ); 完成后,我需要/希望能够卸载此程序集 感谢您的帮助。对于.net core 3.0及更高版本: 现在可以卸载程序集。请注意,appdomains在.net core中不再可用。相反,您可以创建一个或多个AssemblyLoadContext,通过该上下文加载程序集,然后卸载该上下文。看,或者 适用于.net core 3之前的
var assembly = Assembly.LoadFrom( FilePathHere );
完成后,我需要/希望能够卸载此程序集
感谢您的帮助。对于.net core 3.0及更高版本: 现在可以卸载程序集。请注意,appdomains在.net core中不再可用。相反,您可以创建一个或多个AssemblyLoadContext,通过该上下文加载程序集,然后卸载该上下文。看,或者 适用于.net core 3之前的.net版本,包括netframework 4及更低版本 无法从appdomain卸载程序集。您可以销毁appdomain,但一旦将程序集加载到appdomain中,它将在appdomain的生命周期中一直存在 参见Jason Zander对
如果您使用的是3.5,那么可以使用AddIn框架使管理/调用不同的AppDomain变得更容易(您可以卸载AppDomain,卸载所有程序集)。如果您使用的是之前的版本,则需要自己创建一个新的appdomain来卸载它。如果不卸载整个appdomain,则无法卸载程序集:
如果您想拥有可以在以后卸载的临时代码,根据您的需要,
DynamicMethod
类可能会执行您想要的操作。但是,这不会给您提供类。您应该将临时程序集加载到另一个AppDomain
中,当不使用时,您可以卸载该AppDomain
。它既安全又快速。下面是一个很好的示例,说明如何在运行时编译和运行dll,然后卸载所有资源:
我知道它很古老,但可能会帮助别人。您可以从流中加载文件并释放它。这对我有用。我找到了解决办法
希望能有所帮助。我也知道这是一个很老的问题,但可能会帮助有这个问题的人! 这是我找到的一种方法! 而不是使用:
var assembly = Assembly.LoadFrom( FilePathHere );
使用以下命令:
var assembly = Assembly.Load( File.ReadAllBytes(FilePathHere));
这实际上是加载程序集文件的“内容”,而不是加载文件本身。这意味着部件文件上没有放置文件锁!因此,现在可以复制、删除或升级它,而无需关闭应用程序或尝试使用单独的AppDomain或封送
优点:用一行代码修复非常简单!
缺点:无法使用AppDomain、Assembly.Location或Assembly.CodeBase
现在您只需要销毁在程序集上创建的任何实例。
例如:
assembly = null;
另一种选择是,如果程序集刚刚加载,要检查程序集的信息(如公钥),更好的方法是不加载它,而是先加载AssemblyName来检查信息:
AssemblyName an = AssemblyName.GetAssemblyName ("myfile.exe");
byte[] publicKey = an.GetPublicKey();
CultureInfo culture = an.CultureInfo;
Version version = an.Version;
编辑
如果您需要反映程序集中的类型而不将程序集放入应用程序域,则可以使用assembly.ReflectionOnlyLoadFrom
方法。
这将允许您查看程序集中的类型,但不允许您实例化它们,也不会将程序集加载到AppDomain中
将此示例视为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
}
我认为.Net 3.5改变了这一点?没有计划允许从应用程序域卸载程序集(我也不希望他们这样做,这很难做到,关心的人会使用更安全、更干净的解决方法)。你能做的最好的是轻量级代码生成器,Khoth提到不要使用LoadFrom,它与Load上下文处于不同的上下文中,可能会导致问题。这个问题问得好,但我看不到关于如何解析var assembly=assembly.LoadFrom(FilePathHere)的任何明确答案;请参见AppDomain.docCallback和MarshalByRefObject:您使用一个方法创建MarshalByRefObject“invoker”,该方法执行您想要的操作并在其可变字段中返回某些内容,您创建一个临时AppDomain并调用dom.DoCallback(invoker.DoSomething)以使该对象执行您想要的操作;然后从appdomain中的调用程序收集结果并卸载临时域。@jkff:不幸的是,如果使用MarshallByRefObject,如乒乓球示例中所示,Assembly.LoadFrom将像在主appdomain中一样执行,因此卸载临时appdomain仍会产生无法卸载程序集的旧问题。我认为,如果您想访问临时AppDomain并仍然能够卸载程序集,您可能必须以某种方式从临时AppDomain序列化所需的数据,而不进行封送处理。@jkff:您可能是对的。。。但它并不像MSDN示例中描述的那样简单。可能应该使用tempAppDomain.CreateInstanceAndUnwrap。。。甚至可能需要使用AppDomain.GetData和SetData。(如果appdomain的唯一用途是加载和卸载,那么它不会真正扰乱appdomain。)“不能使用appdomain”是指不能在该程序集中启动appdomain,或者可以更具体一些?那怎么办