【发布时间】:2015-10-26 21:24:00
【问题描述】:
我有一个问题,我有一个程序应该从 DLL 实现特定基类的特定目录加载插件 (DLL)。问题是我加载 DLL 的程序引用了另一个 DLL,正在加载的 DLL 也引用了该 DLL。我将举例说明问题是如何产生的。这个简单的测试包括 3 个不同的解决方案和 3 个独立的项目。 注意:如果我将所有项目都放在同一个解决方案中,则不会出现问题。
解决方案 1 - 定义基类和接口的项目 AdapterBase.cs
namespace AdapterLib
{
public interface IAdapter
{
void PrintHello();
}
public abstract class AdapterBase
{
protected abstract IAdapter Adapter { get; }
public void PrintHello()
{
Adapter.PrintHello();
}
}
}
解决方案 2 - 定义基类实现的项目 MyAdapter.cs
namespace MyAdapter
{
public class MyAdapter : AdapterBase
{
private IAdapter adapter;
protected override IAdapter Adapter
{
get { return adapter ?? (adapter = new ImplementedTestClass()); }
}
}
public class ImplementedTestClass : IAdapter
{
public void PrintHello()
{
Console.WriteLine("Hello beautiful worlds!");
}
}
}
解决方案 3 - 加载实现 AdapterBase* 的 DLL 的主程序 **Program.cs
namespace MyProgram {
internal class Program {
private static void Main(string[] args) {
AdapterBase adapter = LoadAdapterFromPath("C:\\test\\Adapter");
adapter.PrintHello();
}
public static AdapterBase LoadAdapterFromPath(string dir) {
string[] files = Directory.GetFiles(dir, "*.dll");
AdapterBase moduleToBeLoaded = null;
foreach (var file in files) {
Assembly assembly = Assembly.LoadFrom(file);
foreach (Type type in assembly.GetTypes()) {
if (type.IsSubclassOf(typeof(AdapterBase))) {
try {
moduleToBeLoaded =
assembly.CreateInstance(type.FullName, false, BindingFlags.CreateInstance, null, null,
null, null) as AdapterBase;
} catch (Exception ex) {
}
if (moduleToBeLoaded != null) {
return moduleToBeLoaded;
}
}
}
}
return moduleToBeLoaded;
}
}
}
所以现在主程序 MyProgram.cs 将尝试从路径 C:\test\Adapter 加载 DLL,如果我 仅 将文件 MyAdapter.dll 放在该文件夹中。但是解决方案 2 (MyAdapter.cs) 会将 MyAdapter.dll 和 AdapterBase.dll 都放在输出 bin/ 目录中。现在,如果将这两个文件都复制到 c:\test\Adapter,则 DLL 中的实例不会因为比较而被加载 if (type.IsSubclassOf(typeof(AdapterBase))) { 在 MyProgram.cs 中失败。
由于 MyProgram.cs 已经引用了 AdapterBase.dll,因此从引用相同 DLL 的不同路径加载的其他 DLL 似乎存在一些冲突。加载的 DLL 似乎首先解决了它对同一文件夹中 DLL 的依赖关系。我认为这与程序集上下文和 LoadFrom 方法的一些问题有关,但我不知道如何让 C# 意识到它实际上是它已经加载的同一个 DLL。
一个解决方案当然只是复制唯一需要的 DLL,但如果我的程序能够处理其他共享 DLL 也在那里,它会更加健壮。我的意思是它们实际上是一样的。那么有什么解决方案可以让这更健壮吗?
【问题讨论】: