在多个应用程序域中加载多个程序集版本

3
我的目标是在多个版本的某个程序集上执行一些“代码片段”。我这样做的方式是在单独的应用程序域中执行该“代码片段”,每个程序集版本一个应用程序域。
只有在“代码片段”通过反射使用程序集时,我才能做到这一点,但我想要的是以强类型方式编写该“代码片段”。
换句话说,假设我有以下程序集:
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。


如果它是一个强名称程序集,并且您在加载应用程序之前知道版本,您可以使用绑定重定向并在app/web .config文件中更改版本。 - Abdul Rehman Sayed
“strongly typed” 与 “multiple versions” 是截然相反的。.NET通过在类型标识中包含程序集版本号来实现强类型检查。这是一种强大的DLL Hell对策,但显然您不想故意制造混乱。因此,您根本不想这样做。 - Hans Passant
是的,没错。基本上,我想忽略dll-hell保护和强名称。 - bellpatricia
1个回答

1

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

  • 它无法将两个具有相同名称的类从不同的程序集载入到同一命名空间中。
  • 由于路径或文件名不是程序集引用的一部分,因此您不能在编译时使用相同的强名称引用两个程序集。

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

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

使用这个技巧,您的应用程序中将保留相同的动态墙,但您可以缩小您正在动态使用的接口。


谢谢您的回复,不幸的是,您证实了我的担忧。尽管如此,感谢您提出的解决方案。 - bellpatricia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接