我的目标是在该程序集的多个版本上执行一些使用某些程序集的“代码段”。我这样做的方式是在单独的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/
├─ /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());
}
这可能吗?
我的问题是,使用某些特定版本的ClassLibrary1(可能是最新版本)编写PieceOfCode,但我看不到如何在单独的AppDomain中“覆盖”该版本。
我尝试了几件事,但是我总是以FileLoadException结尾。
最佳答案
不幸的是,当您在静态类型的代码段中编写ClassLibrary1.Class1
时,需要一个程序集引用,并且编译器使用该引用来命名该类的给定版本。尽管完全限定名称(typeof(Class1).AssemblyQualifiedName
)不包含程序集的路径或文件名,而仅包含程序集名称和版本,但类加载器还有其他限制,您可能会注意到:
它不能将具有相同名称的不同程序集中的2个类加载到同一名称空间中
由于路径或文件名不是程序集引用的一部分,因此不能引用两个具有相同强名称的程序集编译时
使用Assembly.LoadFrom(...)
和动态绑定的方式是我能想到的最好的方式。这就是通常从集成它们的应用程序中对待不同版本的Office程序集的方法。
我看到的唯一可能的解决方案是将一段代码分离到一个单独的程序集中(例如,MyStaticIntegration.dll),针对每个版本的依赖项(ClassLibrary1.dll)分别对其进行编译,然后将每个版本的MyStaticIntegration.dll集成到您的应用程序中。与之前使用ClassLibrary1.dll进行操作的方式相同。
相同的动态墙将保留在您的应用程序中,但是您可以使用此技巧来缩小动态使用的界面的范围。