【问题标题】:MEF, why are identical duplicates of one and the same exported plugin created?MEF,为什么会创建一个相同的导出插件的相同副本?
【发布时间】:2013-05-07 09:04:55
【问题描述】:

(1) 使用下面的代码,我的容器中正好有 2 个项目,其中包含一个相同的导出插件,我想知道为什么:

(2) 我真的无法实现的其他问题:如何扩展框架以处理不同的插件类型(例如具有多个不同类型的导入,或者一个将所有插件存储在动态 IEnumerable 左右的导入)。我想在我的静态包装类中提供一种通用方法,该方法将发现的插件作为类型和匹配元数据的函数返回。

导出的插件(驻留在单独的 dll 中,并且在构建 DirectoryCatalog 时指向其位置。

[Export(typeof(IPlugin))] //<---- If this line is commented out then only one item is imported (why?)
[PluginAttribute(typeof(StrategyPlugin_Test1), "StrategyPlugin", "Plugin1")]
public class StrategyPlugin_Test1 : IPlugin
{
    public void DoSomething()
    {
        Console.WriteLine("I do something");
    }
}

以下代码定义了强类型元数据和导入,以及一个执行 MEF 功能的静态类,并且应该包含已发现的插件:

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class PluginAttribute : ExportAttribute
{
    public Type PluginType { get; set; }
    public string PluginGroupName { get; set; }
    public string PluginName { get; set; }

    public PluginAttribute(Type pluginType, string pluginGroupName, string pluginName) : base(typeof(IPlugin))
    {
        PluginType = pluginType;
        PluginGroupName = pluginGroupName;
        PluginName = pluginName;
    }
}

public interface IPluginAttribute
{
    Type PluginType { get; }
    string PluginGroupName { get; }
    string PluginName { get; }
}

public interface IPlugin
{
    void DoSomething();
}

public class PluginDefinition
{
    [ImportMany(typeof(IPlugin))]
    public IEnumerable<Lazy<IPlugin, IPluginAttribute>> Plugins { get; set; }

    public PluginDefinition()
    {

    }
}

这里是封装了一些核心 MEF 内容的静态类:

public static class PluginManager
{
    private static PluginDefinition PluginDefinitions { get; set; }

    static PluginManager()
    {}

    public static void Configure(PluginDefinition pluginDefinitions, IEnumerable<string> pluginDirectories)
    {
        AggregateCatalog aggregateCatalog = new AggregateCatalog(new DirectoryCatalog(pluginDirectories.FirstOrDefault()));
        CompositionContainer container = new CompositionContainer(aggregateCatalog);
        container.ComposeParts(pluginDefinitions);

        //store plugin definition
        PluginDefinitions = pluginDefinitions;


    }

    public static T GetPlugin<T>(string pluginName, string pluginGroupName) where T : class
    {
        //how to implement this given type of T could be any of the plugin types ...
        //...provided for in an extended PluginDefinition class?

        return null;
    }

}

【问题讨论】:

    标签: c# plugins reflection mef .net-assembly


    【解决方案1】:

    重复导出背后的原因是您从ExportAttribute 派生自定义导出元数据属性。这意味着当你用PluginAttribute装饰一个类成员时,你不需要添加ExportAttribute。 MEF 将查找可分配给ExportAttribute 的属性,并会在您的PluginAttribute 中找到一个。

    关于插件类型的其他问题,MEF 允许在同一类型上进行多个导出。您可以有一个 IPlugin 类型的导出和另一个更专业的导出,就像您在代码中所做的那样:

    [Export(typeof(IPlugin))] //<---- If this line is commented out then only one item is imported (why?)
    [PluginAttribute(typeof(StrategyPlugin_Test1), "StrategyPlugin", "Plugin1")]
    public class StrategyPlugin_Test1 : IPlugin
    

    然后对每种导出类型有不同的导入。您可以先导入 IEnumerable&lt;IPlugin&gt;,然后在另一个属性上导入 StrategyPlugin_Test1

    【讨论】:

    • 感谢您的 cmets,您回答了我的第一个问题。但是,我不清楚您对 IEnumerable&lt;IPlugin&gt; 的含义。稍后我还将能够处理其他类库(插件),这些类库(插件)不仅派生自IPlugin,而且还派生自其他接口。
    • 我通过完全不指定任何导入属性解决了这个问题。相反,我懒惰地组合容器中的所有部分,当通用访问方法请求实例时,它将枚举容器中的导出,并且仅在类型和其他元数据匹配时才初始化并返回实例。这样,我什至不必指定我正在处理的插件类型。要么满足请求并返回所请求的泛型类型的请求实例,要么方法返回 null。这样一来,MEF 实际上是相当漂亮的,我喜欢我目前所看到的。
    • @Freddy 太好了!感谢分享。
    猜你喜欢
    • 1970-01-01
    • 2015-06-17
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 2015-08-17
    • 2020-07-18
    • 2020-02-23
    • 1970-01-01
    相关资源
    最近更新 更多