动态加载和卸载c#程序集到appdomain

时间:2017-10-10 08:06:30

标签: c# .net .net-assembly

有很多类似的问题。但是它们已经岁了多年,今天不再工作了(不再?)。

所以这是我的问题: 我想将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.

现在,在写这个问题时,我做了一些测试 - 我试图找出为什么我不能删除汇编文件。我发现它被视觉工作室远程调试器锁定了。

所以第二个问题是:如何避免使用远程调试器锁定文件?

1 个答案:

答案 0 :(得分:3)

我发现Assembly.LoadFile(...)会锁定文件,甚至超出了卸载AppDomain的程度。

我的解决方案是首先将汇编字节加载到内存中,然后将其加载到AppDomain中:

var assemblyBytes = System.IO.File.ReadAllBytes("myassembly.dll");
var assembly = System.Reflection.Assembly.Load(assemblyBytes);

这样文件永远不会被锁定,你可以删除它等等。

对类似问题here有更好的答案。