gpt4 book ai didi

c# - 如何从在 C# 中实现特定基类的 DLL 正确加载实例?

转载 作者:行者123 更新时间:2023-11-30 16:51:55 26 4
gpt4 key购买 nike

我有一个问题,我有一个程序应该从特定目录加载插件 (DLL),其中 DLL 实现特定基类。问题是我加载 DLL 的程序引用了另一个 DLL,被加载的 DLL 也引用了该 DLL。我将举例说明问题是如何产生的。这个简单的测试包含 3 个不同的解决方案和 3 个独立的项目。 注意:如果所有项目都在同一个解决方案中,则不会出现此问题。

解决方案 1 - 定义基类和接口(interface)的项目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 的主程序***程序.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,如果我 ONLY 将文件 MyAdapter.dll 放入该文件夹中。但是解决方案 2 (MyAdapter.cs) 会将 MyAdapter.dllAdapterBase.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 也在那里,它会更加健壮。我的意思是他们实际上是一样的。那么任何解决方案如何做到这一点更强大?

最佳答案

是的,这是一个类型标识问题。 .NET 类型的标识不仅仅是命名空间和类型名称,它还包括它来自的程序集。您的插件依赖于包含 IAdapter 的程序集,当 LoadFrom() 加载插件时,它也将需要该程序集。 CLR 在 LoadFrom 上下文中找到它,换句话说,在 c:\test\adapter 目录中,通常非常需要,因为它允许插件使用它们自己的 DLL 版本。

只是在这种情况下不是。这是错误的,因为您的插件解决方案尽职地复制了依赖项。通常非常可取,只是在这种情况下不是。

您必须阻止它复制 IAdapter 程序集:

  • 打开插件解决方案并使用 Build > Clean。
  • 使用资源管理器删除输出目录中 IAdapter 程序集的剩余副本。
  • 在插件解决方案的引用节点中选择 IAdapter 程序集。将其 Copy Local 属性设置为 False。
  • 使用 Build > Build 并验证 IAdapter 程序集确实不再被复制。

Copy Local 是本质,其余的项目符号只是为了确保旧副本不会导致问题。由于 CLR 无法再“轻松地”找到 IAdapter 程序集,因此它被迫继续寻找它。现在在 Load 上下文中找到它,换句话说,在安装主机可执行文件的目录中。已经加载,无需再次加载唯一。问题解决了。

关于c# - 如何从在 C# 中实现特定基类的 DLL 正确加载实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33280878/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com