C#插件架构,接口在插件之间共享

时间:2009-05-06 13:36:08

标签: c# plugins interface observer-pattern

5 个答案:

答案 0 :(得分:15)

我只是尝试尽可能地重新创建您的解决方案,而且我没有这样的问题。 (警告,大量代码示例如下......)

第一个项目是应用程序,它包含一个类:

public class PluginLoader : ILoader
{
    private List<Type> _providers = new List<Type>();

    public PluginLoader()
    {
        LoadProviders();
        LoadConsumers();
    }

    public IProvider RequestProvider(Type providerType)
    {
        foreach(Type t in _providers)
        {
            if (t.GetInterfaces().Contains(providerType))
            {
                return (IProvider)Activator.CreateInstance(t);
            }
        }
        return null;
    }

    private void LoadProviders()
    {
        DirectoryInfo di = new DirectoryInfo(PluginSearchPath);
        FileInfo[] assemblies = di.GetFiles("*.dll");
        foreach (FileInfo assembly in assemblies)
        {
            Assembly a = Assembly.LoadFrom(assembly.FullName);
            foreach (Type type in a.GetTypes())
            {
                if (type.GetInterfaces().Contains(typeof(IProvider)))
                {
                    _providers.Add(type);
                }
            }
        }

    }

    private void LoadConsumers()
    {
        DirectoryInfo di = new DirectoryInfo(PluginSearchPath);
        FileInfo[] assemblies = di.GetFiles("*.dll");
        foreach (FileInfo assembly in assemblies)
        {
            Assembly a = Assembly.LoadFrom(assembly.FullName);
            foreach (Type type in a.GetTypes())
            {
                if (type.GetInterfaces().Contains(typeof(IConsumer)))
                {
                    IConsumer consumer = (IConsumer)Activator.CreateInstance(type);
                    consumer.Initialize(this);
                }
            }
        }
    }

显然,这可以大大整理。

下一个项目是共享库,它包含以下三个接口:

public interface ILoader
{
    IProvider RequestProvider(Type providerType);
}

public interface IConsumer
{
    void Initialize(ILoader loader);
}

public interface IProvider
{
}

最后有一个包含这些类的插件项目:

public interface ITest : IProvider
{        
}

public class TestConsumer : IConsumer
{
    public void Initialize(ILoader loader)
    {
        ITest tester = (ITest)loader.RequestProvider(typeof (ITest));
    }
}

public class TestProvider : ITest
{        
}

应用程序和插件项目都引用共享项目,插件dll被复制到应用程序的搜索目录中 - 但它们不会相互引用。

当构造PluginLoader时,它会找到所有的IProviders然后创建所有IConsumers并调用它们的Initialize。在初始化内部,消费者可以从加载器请求提供者,并且在此代码的情况下,构造并返回TestProvider。所有这些对我来说都是有效的,没有花哨的控制装配的装载。

答案 1 :(得分:4)

它仍在开发中,但听起来像是MEF的完美用例(包含在.Net 4中),并在VS2010内部使用。

  

MEF提供了一个简单的解决方案   运行时可扩展性问题。直到   现在,任何想要的应用程序   支持所需的插件模型   从中创建自己的基础架构   刮。那些插件经常是   特定于应用程序,但不可能   重复使用多个   的实施方式。

预览已在http://www.codeplex.com/MEF

上提供

Glen Block的blog也很有用。

答案 2 :(得分:2)

您可能会发现我的文章对于查看插件框架的工作示例很有用,以及如何通过创建包含接口的公共程序集来解决这些问题:

C#Basic教程中的插件:

http://www.codeproject.com/KB/cs/pluginsincsharp.aspx

后续文章,启用了Generics插件管理器库:

http://www.codeproject.com/KB/cs/ExtensionManagerLibrary.aspx

答案 3 :(得分:0)

如果您有疑问,两个不相关的程序集如何共享同一个接口,答案是“您不能”解决方案是在所有程序集中包含接口,也许在插件构建器可以引用的dll中,并在装载组件中。

答案 4 :(得分:0)

我做了类似于你想要做的事情,只要我在自动装载机看到的地方装配了组件,我就没有遇到任何问题。

您是否尝试将所有程序集放在exe所在的子目录下?我现在不记得细节,但是有一个步骤列表,记录了加载器查找装配体/类型的确切位置和顺序。