将 c# 程序集动态加载和卸载到 appdomain
Posted
技术标签:
【中文标题】将 c# 程序集动态加载和卸载到 appdomain【英文标题】:dynamically loading and unloading of c# assembly into appdomain 【发布时间】:2017-10-10 08:06:29 【问题描述】:类似的问题还有很多。但他们都老了,今天不工作了(不再工作了?)。
所以这是我的问题: 我想将一个 c# 程序集加载到内存中,并找出它是否包含与我要使用的接口匹配的类型。如果程序集包含此类类型,我会在我的主应用程序中引用并使用它。如果没有,我想卸载 dll,然后能够删除文件(从我的主应用程序或在应用程序运行时手动删除)。
我的第一个实现只是省略了 appdomain 方法,但它确实有效(没有删除或替换汇编文件)。然后我尝试按照各种示例中的描述加载程序集。但是没有我能够从磁盘中删除不需要的程序集文件。
要么在应用程序中引用程序集时根本无法卸载和删除程序集,要么我做错了什么。 这是我最后尝试的:
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
using ESTLogViewer_V2.Formulare;
using Parent;
namespace ESTLogViewer_V2
static class Program
//<summary>
//Der Haupteinstiegspunkt für die Anwendung.
//</summary>
[STAThread]
static void Main()
LoadTest.Haupt(null);
namespace Parent
public class Constants
// adjust
public const string LIB_PATH = @"e:\PRJDOTNET4\ESTLogViewer V2\Plugins\LogFiles_Plugin.dll";
public interface ILoader
string Execute();
public class Loader : MarshalByRefObject, ILoader
public string Execute()
var assembly = Assembly.LoadFile(Constants.LIB_PATH);
foreach (var t in assembly.GetTypes())
Debug.WriteLine(t.FullName);
return assembly.FullName;
class LoadTest
public static void Haupt(string[] args)
var domain = AppDomain.CreateDomain("child");
var loader = (ILoader)domain.CreateInstanceAndUnwrap(typeof(Loader).Assembly.FullName, typeof(Loader).FullName);
Console.Out.WriteLine(loader.Execute());
AppDomain.Unload(domain);
domain = null;
File.Delete(Constants.LIB_PATH);
因此,此代码在 File.Delete
语句之前有效。但随后它抛出了一个异常:
LogFiles_Plugin.clsSchritLogDateiSplitter
LogFiles_Plugin.clsLogFileMeldDateiSplitter
LogFiles_Plugin.clsLogFileMeldDateiSplitterNG
LogFiles_Plugin.clsAuftragsAnalyseSplitter
LogFiles_Plugin.clsAuftrag
LogFiles_Plugin.clsS_R_SignalSplitter
LogFiles_Plugin.clsLogFileGVMeldDateiSplitter
LogFiles_Plugin.clsLogFileGVTeleSplitter
LogFiles_Plugin.clsLogFileGVTeleSplitter+spalte
<PrivateImplementationDetails>37CEBF0C-E73A-4FE7-B152-9A858E6C176D
<PrivateImplementationDetails>37CEBF0C-E73A-4FE7-B152-9A858E6C176D+__StaticArrayInitTypeSize=6256
"ESTLogViewer V2.exe" (Verwaltet (v4.0.30319)): "C:\Windows\Microsoft.Net\assembly\GAC_MSIL\mscorlib.resources\v4.0_4.0.0.0_de_b77a5c561934e089\mscorlib.resources.dll" geladen
Eine Ausnahme (erste Chance) des Typs "System.UnauthorizedAccessException" ist in mscorlib.dll aufgetreten.
现在,在写这个问题的时候,我做了更多的测试——我试图找出为什么我不能删除程序集文件。我发现它被visual studio远程调试器锁定了。
那么第二个问题是:如何避免使用远程调试器锁定文件?
【问题讨论】:
相关帖子 - How to unload an assembly from the primary AppDomain? 【参考方案1】:我发现Assembly.LoadFile(...)
会锁定文件,甚至超出了卸载 AppDomain 的范围。
我的解决方案是先将程序集字节加载到内存中,然后再加载到AppDomain中:
var assemblyBytes = System.IO.File.ReadAllBytes("myassembly.dll");
var assembly = System.Reflection.Assembly.Load(assemblyBytes);
这样文件永远不会被锁定,你可以删除它,等等。
类似问题here有更好的答案。
【讨论】:
你好@John,我用你的代码替换了我的示例中的代码并且它有效。这是“appdomain”方法的解决方案。但它也应该在不使用 appdomain 的情况下工作。 @WolfgangRoth 虽然它应该适用于两者,但请注意(正如linked answer 所说)除非它位于 AppDomain 中,否则一旦加载程序集就无法卸载它。 MSDN concurs 我还没有研究多次加载程序集的影响。但是我对程序集加载的主要想法是能够在我的代码中实现插件,这些插件可以由用户交换。并且每次用户更新插件列表时,都应该添加新插件,并且应该从显示给用户的列表中删除旧插件 - 可能是,应用程序将无法替换仅在实现上有所不同的程序集,但否则有相同的命名空间和名称......也许明天会试试这个。以上是关于将 c# 程序集动态加载和卸载到 appdomain的主要内容,如果未能解决你的问题,请参考以下文章
C# 通过 AppDomain 应用程序域实现程序集动态卸载或加载
C# 通过 AppDomain 应用程序域实现程序集动态卸载或加载