【问题标题】:Loading of plugin from dll从 dll 加载插件
【发布时间】:2014-02-24 11:07:24
【问题描述】:

我已经开始使用一个简单的插件加载器,它监视一个目录并在其中的 dll 包含 IPlugin 接口时加载插件。

public class PluginLoader : Dictionary<string, IPlugin>
{
    private FileSystemWatcher watcher;
    private string pluginPath;

    public PluginLoader()
        : base()
    {            
        pluginPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "plugins");
        if (!Directory.Exists(pluginPath))
            Directory.CreateDirectory(pluginPath);

        watcher = new FileSystemWatcher(pluginPath, "*.dll");
        watcher.IncludeSubdirectories = true;
        watcher.Created += watcher_Created;
        watcher.EnableRaisingEvents = true;
    }        

    private void watcher_Created(object sender, FileSystemEventArgs e)
    {
        LoadPlugin(e.FullPath);
    }

    private void LoadPlugin(string path)
    {            
        IPlugin plugin = null;
        Assembly assembly = Assembly.LoadFrom(path);

        foreach (Type type in assembly.GetExportedTypes())
        {
            if (type.IsClass && type.GetInterfaces().Count(iType => iType == typeof(IPlugin)) == 1)
            {
                ConstructorInfo constructor = type.GetConstructor(new Type[] { });
                object instance = constructor.Invoke(new object[] { });
                plugin = instance as IPlugin;
                // plugin is now not null
            }
        }
        if (plugin != null && !this.ContainsKey(plugin.PluginName))
        {
            this[plugin.PluginName] = plugin;
        }
    }        
}    

此版本的 LoadPlugin() 有效,插件变量最终为 != null。但是,这个不起作用:

    private void LoadPlugin(string path)
    {            
        IPlugin plugin = null;
        Assembly assembly = Assembly.LoadFrom(path);

        foreach (Type type in assembly.GetExportedTypes())
        {
            if (type.IsClass && type.GetInterface(typeof(IPlugin).FullName) != null)
            {
                ConstructorInfo constructor = type.GetConstructor(new Type[] { });
                object instance = constructor.Invoke(new object[] { });
                plugin = instance as IPlugin;
                // plugin is still null
            }
        }
        if (plugin != null && !this.ContainsKey(plugin.PluginName))
        {
            this[plugin.PluginName] = plugin;
        }
    }

我只是不明白为什么。所以我的问题是:为什么插件在第二个示例中最终为空?

解决方案: 问题是我有两种不同的IPlugin 类型,因为它的组件存在于两个不同的位置。所以删除插件目录下的Framework.Lib.dll就解决了。

【问题讨论】:

  • 加载插件成功后,使用break停止对剩余类型的迭代。

标签: c# .net plugins dll .net-assembly


【解决方案1】:

我能想到的唯一原因是该类型实现了具有相同命名空间但来自不同程序集的IPlugintypeof(IPlugin).FullName 将在您的插件加载器和插件之间匹配,但实现的类型仍然不等于预期的类型。

第一个示例匹配完全相同的类型,在第二个示例中,您匹配的是 FullName,它只包含命名空间,而不是加载类型的程序集。

要确定是否是这种情况,请尝试记录以下值:

bool matches = typeof(IPlugin).IsAssignableFrom(type);
string expected = typeof(IPlugin).AssemblyQualifiedName;
string actual = type.GetInterface(typeof(IPlugin).FullName).AssemblyQualifiedName;

typeof(IPlugin).IsAssignableFrom(type) 可能是您首先要寻找的。​​p>

【讨论】:

  • 预期等于实际,但匹配为假。插件加载器在“Framework”程序集中,IPlugin接口在“Framework.Lib”程序集中,我的测试插件(“Test”程序集)引用“Framework.Lib”并实现IPlugin。
  • string expected = typeof(IPlugin).Location;string actual = type.GetInterface(typeof(IPlugin).FullName).Location; 怎么样?如果IsAssignableFrom() 返回false,那么第一个示例也应该返回null。示例 1 中的第一个匹配类型是否与示例 2 中的第一个匹配类型相同?
  • 是的,位置不同。第一个位置是.\Framework.Lib.dll,第二个位置是.\plugins\testplugin\Framework.Lib.dll。你是对的,第一个例子也应该返回 false 。现在它确实返回 false。我也不知道我“破坏”了什么。
  • 如果你从插件目录中删除Framework.Lib.dll,它仍然运行吗?
  • 当然可以!现在声明type.GetInterface(typeof(IPlugin).FullName) != nulltype.GetInterfaces().Count(iType =&gt; iType == typeof(IPlugin)) == 1typeof(IPlugin).IsAssignableFrom(type) 是正确的。我想我现在明白了.. 谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-22
  • 2011-08-22
  • 1970-01-01
  • 2020-02-25
  • 1970-01-01
  • 2011-09-01
相关资源
最近更新 更多