将多个程序集版本加载到多个 AppDomains
Load multiple assembly versions into multiple AppDomains
我的目标是执行一些“一段代码”,它使用某个程序集,在该程序集的多个版本上。我这样做的方法是在单独的 AppDomains 上执行 "piece of code",每个程序集版本一个。
只有当“一段代码”通过反射使用程序集时我才能做到这一点,但我想要的是让“一段代码”以强类型方式编写。
换句话说,假设我有以下程序集:
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
现在执行 "piece of code" 我正在使用以下控制台应用程序:
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(可能是最新的)编写,我看不出如何 "override" 在单独的 AppDomain 中使用该版本。
我尝试了一些东西,但我总是以 FileLoadException 结束。
不幸的是,当您在一段静态类型的代码中编写 ClassLibrary1.Class1
时,您需要一个程序集引用,并且编译器使用该引用来命名 class 的给定版本。尽管完全限定名称 (typeof(Class1).AssemblyQualifiedName
) 不包含程序集的路径或文件名,仅包含程序集名称和版本,但您可能会注意到 class 加载程序还有更多限制:
- 它无法将来自不同程序集的 2 个 classes 加载到同一个命名空间中
- 由于路径或文件名不是程序集引用的一部分,您不能在编译时引用具有相同强名称的 2 个程序集
您使用 Assembly.LoadFrom(...)
和动态绑定的方式是我能想到的最好的方式。这就是集成它们的应用程序通常如何处理不同版本的 Office 程序集。
我看到的唯一可能的解决方案是将 一段代码 分成一个单独的程序集(例如,MyStaticIntegration.dll)针对您的依赖项的每个版本编译它(ClassLibrary1.dll) 分开,然后将 MyStaticIntegration.dll 的每个版本集成到您的应用程序中,就像之前使用 ClassLibrary1.dll 一样。
相同的动态墙将保留在您的应用程序中,但您可以使用此技巧缩小动态使用的界面。
我的目标是执行一些“一段代码”,它使用某个程序集,在该程序集的多个版本上。我这样做的方法是在单独的 AppDomains 上执行 "piece of code",每个程序集版本一个。
只有当“一段代码”通过反射使用程序集时我才能做到这一点,但我想要的是让“一段代码”以强类型方式编写。
换句话说,假设我有以下程序集:
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
现在执行 "piece of code" 我正在使用以下控制台应用程序:
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(可能是最新的)编写,我看不出如何 "override" 在单独的 AppDomain 中使用该版本。 我尝试了一些东西,但我总是以 FileLoadException 结束。
不幸的是,当您在一段静态类型的代码中编写 ClassLibrary1.Class1
时,您需要一个程序集引用,并且编译器使用该引用来命名 class 的给定版本。尽管完全限定名称 (typeof(Class1).AssemblyQualifiedName
) 不包含程序集的路径或文件名,仅包含程序集名称和版本,但您可能会注意到 class 加载程序还有更多限制:
- 它无法将来自不同程序集的 2 个 classes 加载到同一个命名空间中
- 由于路径或文件名不是程序集引用的一部分,您不能在编译时引用具有相同强名称的 2 个程序集
您使用 Assembly.LoadFrom(...)
和动态绑定的方式是我能想到的最好的方式。这就是集成它们的应用程序通常如何处理不同版本的 Office 程序集。
我看到的唯一可能的解决方案是将 一段代码 分成一个单独的程序集(例如,MyStaticIntegration.dll)针对您的依赖项的每个版本编译它(ClassLibrary1.dll) 分开,然后将 MyStaticIntegration.dll 的每个版本集成到您的应用程序中,就像之前使用 ClassLibrary1.dll 一样。
相同的动态墙将保留在您的应用程序中,但您可以使用此技巧缩小动态使用的界面。