动态加载DLL中的接口

8

我正在学习如何将DLL动态加载到C#程序中。思路是,DLL将包含一个接口和若干个实现该接口的类,这样如果我想要添加新的实现,就不必重新编译整个项目。

于是我创建了这个测试。以下是我的DLL文件:

namespace TestDLL
{
  public interface Action
  {
    void DoAction();
  }

  public class PrintString : Action
  {
    public void DoAction()
    {
      Console.WriteLine("Hello World!");
    }
  }

  public class PrintInt : Action
  {
    public void DoAction()
    {
      Console.WriteLine("Hello 1!");
    }
  }
}

而在我的主程序中,我尝试做如下操作:
static void Main(string[] args)
{
  List<Action> actions = new List<Action>();
  Assembly myDll = Assembly.LoadFrom("TestDLL.dll");
  Type[] types = myDll.GetExportedTypes();

  for (int i = 0; i < types.Length; i++)
  {
    Type type = types[i];
    if (type.GetInterface("TestDLL.Action") != null  && type != null)
    {
        Action new_action = myDll.CreateInstance(type.FullName) as Action;
        if (new_action != null)
          actions.Add(new_action);
        else
          Console.WriteLine("New Action is NULL");
    }
  }

  foreach (Action action in actions)
    action.DoAction();
}

我遇到的问题是,尽管

type.FullName

包含正确的值(例如"TestDLL.PrintString"),

这行代码

myDll.CreateInstance(type.FullName) as Action

始终返回 null。

我不确定问题是什么,或者我该如何解决它。

就像例子中一样,我希望能够向 DLL 添加新的 Action 实现,并使主程序在每个实现上调用 DoAction(),而无需重新编译原始程序。希望这样说得清楚!


你在这里使用的Action,在as Action中定义在哪里?你是在引用第一个代码所代表的程序集,还是Action被声明了两次,一次在从TestDLL.dll加载的程序集中,一次在你的主项目中? - Lasse V. Karlsen
2个回答

3
通过您的主要实现,您最好这样做。
            List<object> actions = new List<object>();
            Assembly myDll = Assembly.LoadFrom("TestDLL.dll");
            Type[] types = myDll.GetTypes();

            for (int i = 0; i < types.Length; i++)
            {
                Type type = myDll.GetType(types[i].FullName);
                if (type.GetInterface("TestDLL.Action") != null)
                {
                    object obj = Activator.CreateInstance(type);
                    if (obj != null)
                        actions.Add(obj);
                }
            }

            foreach (var action in actions)
            {
                MethodInfo mi = action.GetType().GetMethod("DoAction");
                mi.Invoke(action, null);
            }

你应该将这个代码块放在try/catch块中。当你写Action(因为你没有将引用设置到你的程序集中),比如 List<Action>,这里的Action是指代Action委托。


3
很可能您的Action在主程序和“其他”程序集中都有定义,并且您正在使用错误的程序集进行转换。
通常,共享接口是在单独的程序集(“SDK”)中定义,并链接到主应用程序和插件程序集。通过源代码共享接口无效,因为类的标识包括类型名称和程序集名称。
更多信息请参见:Cannot get types by custom attributes across assemblies

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