将多个程序集版本加载到多个AppDomain中

时间:2017-10-08 11:42:19

标签: c# .net-assembly appdomain

我的目标是在该程序集的多个版本上执行一些“代码”,它使用某些程序集。我这样做的方法是在单独的AppDomain上执行“一段代码”,每个汇编版本一个。

我只能在“代码”通过反射使用程序集时才能这样做,但我想要的是“代码片段“以强烈的方式写作。

换句话说,假设我有以下程序集:

namespace ClassLibrary1
{
    public class Class1
    {
        internal const string Version = "1.0.0.0";
        public string Method1() { return Version; }
    }
}

它在AssemblyInfo.cs中也有以下定义:

[assembly: AssemblyVersion(ClassLibrary1.Class1.Version)]

现在假设我有一个“Versions”文件夹,其中我有该程序集的多个版本,例如:

/Versions/
├─ /1000/
│   └─ ClassLibrary1.dll
├─ /1001/
│   └─ ClassLibrary1.dll
└─ /1002/
    └─ ClassLibrary1.dll  

现在执行“一段代码”我正在使用以下控制台应用程序:

class Program
{
    static void PieceOfCode(Assembly assembly)
    {
        Type class1Type = assembly.GetType("ClassLibrary1.Class1");
        dynamic class1 = Activator.CreateInstance(class1Type);
        string vesion = class1.Method1();

        Console.WriteLine(vesion);
    }

    public sealed class SeparateDomainExecutor : MarshalByRefObject
    {
        public void Execute(Action<Assembly> action, string assemblyPath)
        {
            action(Assembly.LoadFrom(assemblyPath));
        }
    }

    static void Main(string[] args)
    {
        foreach (string file in Directory.EnumerateFiles(@"C:\Versions", "*.dll", SearchOption.AllDirectories))
        {
            AppDomain domain = AppDomain.CreateDomain("ClassLibrary1 Domain");

            var type = typeof(SeparateDomainExecutor);
            var runner = (SeparateDomainExecutor)domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
            runner.Execute(PieceOfCode, file);

            AppDomain.Unload(domain);
        }

        Console.Read();
    }
}

控制台应用程序运行正常,但我想用“PieceOfCode”中的反射用法替换为以下内容:

static void PieceOfCode()
{
    ClassLibrary1.Class1 class1 = new ClassLibrary1.Class1();
    Console.WriteLine(class1.Method1());
}

这可能吗?

我遇到的问题是PieceOfCode将使用某个特定版本的ClassLibrary1(可能是最新版本)编写,我不知道如何在单独的AppDomain中“覆盖”该版本。 我尝试了一些东西,但我总是以FileLoadException结束。

1 个答案:

答案 0 :(得分:1)

不幸的是,当您在静态类型的代码中编写ClassLibrary1.Class1时,您需要一个程序集引用,编译器使用该引用来命名该类的给定版本。虽然完全限定名称(typeof(Class1).AssemblyQualifiedName)不包含程序集的路径或文件名,只包含程序集名称和版本,但类加载器还有其他限制,如您所知:

  • 它无法将具有相同名称的不同程序集中的2个类加载到同一名称空间
  • 由于路径或文件名不是程序集引用的一部分,因此无法引用具有相同强名称的2个程序集编译时间

您使用Assembly.LoadFrom(...)和动态绑定的方式是我能想到的最好方法。这就是通常从集成它们的应用程序处理不同版本的Office程序集的方式。

我看到的唯一可能的解决方案是将代码片段分成单独的程序集(例如,MyStaticIntegration.dll),分别针对每个版本的依赖项(ClassLibrary1.dll)进行编译,然后进行集成每个版本的MyStaticIntegration.dll进入你的应用程序的方式与之前使用ClassLibrary1.dll的方式相同。

同样的动态墙将保留在您的应用程序中,但您可以使用此技巧动态缩小您正在使用的界面。