如何在运行时引用DLL?

9

我正在使用WPF和C#构建一个应用程序,基本上我想允许任何人创建一个dll并将其放入文件夹中(类似于插件)。该应用程序将获取文件夹中的所有dll,加载它们并使用它们的方法(在接口中定义)。

有什么办法可以在运行时引用这些dll吗?还有更好的实现方式吗?

6个回答

12

我已经实现了你所要求的功能,它可以在给定的目录中搜索dll文件,并找到实现特定接口的类。以下是我用来完成此操作的类:

public class PlugInFactory<T>
{
    public T CreatePlugin(string path)
    {
        foreach (string file in Directory.GetFiles(path, "*.dll"))
        {
            foreach (Type assemblyType in Assembly.LoadFrom(file).GetTypes())
            {
                Type interfaceType = assemblyType.GetInterface(typeof(T).FullName);

                if (interfaceType != null)
                {
                    return (T)Activator.CreateInstance(assemblyType);
                }
            }
        }

        return default(T);
    }
}

你只需要像这样使用初始化此类:


   PlugInFactory<InterfaceToSearchFor> loader = new PlugInFactory<InterfaceToSearchFor>();
     InterfaceToSearchFor instanceOfInterface = loader.CreatePlugin(AppDomain.CurrentDomain.BaseDirectory);

如果这个答案或其他答案对您解决问题有帮助,请通过点击复选框将其标记为答案。此外,如果您认为这是一个好的解决方案,请给它投票以表示感谢。只是想提一下,因为在您的其他问题中似乎没有接受答案。

是的,我也想从头开始做这个,你怎么告诉主项目插件有接口方法呢?我的意思是,如果你想使用像objPlugIn.amethod()这样的东西,你怎么告诉主项目这样你才能编译它? - HoBa
该插件需要公开一个接口,以便您知道它能为您提供什么。该接口需要在插件和主项目之间共享,以便两者都了解接口的要求。 - Cole W
你可以通过一个dll来分享它们。 - Cole W
我明白了,我的声望还不够,等我有了足够的声望,我一定会给你点赞的!!谢谢!! - HoBa
在我的情况下,我不必反序列化我创建的对象。这可能值得另一个堆栈溢出问题。 - Cole W
显示剩余4条评论

1

我认为你可以从类似以下的东西开始:

Assembly assembly = Assembly.LoadFrom("Something.dll");
Type type = assembly.GetType("SomeType");
object instanceOfSomeType = Activator.CreateInstance(type);

然后你可以使用它


我会尝试的!有什么想法如何将DLL与主应用程序进行接口?我知道我必须拥有一个接口,但是主应用程序如何知道object instanceOfSomeType = Activator.CreateInstance(type); 有这些方法? - HoBa
@Homero 如同 Cole 的回答一样,您可以在您的情况下使用 GetInterface 方法。 - V4Vendetta

1

看一下MEF。它应该会提供你所需要的。

使用反射也是一个选择,但如果问我,MEF会是更好的选择。


是的,我了解MEF并且可以提供我所需要的内容。然而,我正在尝试学习这种架构如何工作,所以我想要实现它... =D - HoBa

1
我正在做类似的事情,其中客户可能安装不同版本的第三方DLL,尽管名称和位置相同。如果我们没有引用正确的版本,就会失败。我使用反射来识别版本,但我需要修改设置以根据版本使用不同的DAL类,或通过接口使DAL版本无关。
我倾向于选择第二种方法。如果在您的代码中创建一个“虚拟DLL”,实现具有您想要从目标程序集调用的所有方法的接口,并传递接口而不是实际类型作为参数,则应该能够在设计时代码中使用所有方法并基于模拟实现进行编译,甚至进行测试,但当您在运行时加载实际程序集时,可以从真正的程序集获取结果。 如果这对您有效,请告诉我,我也会告诉您。
Joey Morgan

0
  string relative = "ClassLibrary1.dll";
            string absolute = Path.GetFullPath(relative);

            Assembly assembly = Assembly.LoadFile(absolute);
            System.Type assemblytype = assembly.GetType("ClassLibrary1.Class1");
             object []argtoppass={1,2};
          var a =Activator.CreateInstance(assemblytype, argtoppass);
          System.Type type = a.GetType();
          if (type != null)
          {
              string methodName = "add";
              MethodInfo methodInfo = type.GetMethod(methodName);
              object   result = methodInfo.Invoke(a, null);

              int a1 = (int )result;
          }

这是解决方案,而且它运行得非常好 @Homero Barbosa - user2181871

0
以上的答案基本上已经给了你所需要的。你可以尝试在程序启动时加载所有要插入到应用程序中的dll文件:
// note: your path may differ, this one assumes plugins directory where exe is executed
var pluginsDirectory = Path.Combine(AppContext.BaseDirectory, "plugins");
if (Directory.Exists(pluginsDirectory))
{
    var dllPaths = Directory.GetFiles(pluginsDirectory);
    if (dllPaths.Count() > 0)
    {
        foreach (var dllPath in dllPaths)
        {
            Assembly.LoadFrom(Path.Combine("plugins", Path.GetFileName(dllPath)));
        }
    }
    else
    {
        // warn about no dlls
    }
}
else
{
    // warn about no plugins directory
}

如何引用dll及其类型:

// if dll file name is My.Plugin.Assembly.ShortName.dll, then reference as follows
var pluginAssembly = Assembly.Load("My.Plugin.Assembly.ShortName");
var typesInAssembly = pluginAssembly.GetExportedTypes();
var instanceType = typesInAssembly.FirstOrDefault(t => t.Name == "MyClassName");
var instance = Activator.CreateInstance(instanceType, new object[] { "constructorParam1", "constructorParam2" });
instanceType.InvokeMember("MyMethod", BindingFlags.InvokeMethod, null, instance, new object[] { "methodParam1", "methodParam2" });

您可能需要告诉您的应用程序配置来探测您的插件目录。我假设插件有一个子目录,您可以探测子目录路径列表。

...
<runtime>
    <assemblyBinding ...
        <probing privatePath="plugins" />
...

你需要一些东西来告诉你要实现哪种类型(也许是配置映射)。据我所知,接口只会提供一个合同,所有插件都要实现这个合同,以通过反射调用预期的方法。


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