从dll加载插件

时间:2014-02-24 11:07:25

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

我已经开始使用一个简单的插件加载器来监视目录并加载插件,如果其中的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解决了它。

1 个答案:

答案 0 :(得分:1)

我能想到的唯一原因是该类型实现了具有相同命名空间但来自不同程序集的IPlugin。然后typeof(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)可能就是你首先想要的。