2

背景简介:

我的团队决定使用 Microsoft 的托管可扩展性框架 ( MEF ) 来提供可扩展模型,以便将新的“提供者”添加到我们的系统中。

这使我们能够相对轻松地插入新的第 3 方提供商。

注意:MEF 的使用、启动和运行的简单程度给我留下了深刻的印象。

我的问题:

由于这些提供程序通常具有与之关联的不同属性,因此在运行时将这些提供程序加载到系统中时,我们需要访问提供程序的数据流和属性。

由于属性不同,应该采取什么方法来使用所述提供程序插件?注意到他们都做类似的工作。

我的解决方案:

创建提供者必须遵守的接口,从而围绕每个第 3 方提供者创建一个“包装器”,从而为每个提供者提供一致的接口/编程模型。

插件 = 3rd 方数据源(提供者)+ 通用接口实现。

+ve:对于所述插件,不需要更复杂的基于反射的动态“插件”。

-ve:必须为每个提供者编写一个包装器。(无论如何,我们都需要添加 MEF 导出标签)

进一步说明:

对我来说,接口/包装器方法是最简单的,但有人告诉我研究一种基于反射的方法,该方法可以利用反射来发现运行时可以暴露给系统的属性。

我不赞成任何一种解决方案,但我很想听听社区的想法(其中大多数人比我更有经验)。

谢谢。

4

3 回答 3

2

实际上,在预览版 6 中,我们已解封导出,并允许您创建包含元数据的自定义导出属性,从而消除部分作者添加单独导出的需要。我们所有的导入属性也都是未密封的。

[MetadataAttribute]
[AttributeUsage(AllowMultiple=false)] 
public class RuleAttribute : ExportAttribute {
  public RuleAttribute(string name, string description) {
    Name=name;
    Description=description;

  } : base(typeof(IRule))

  public string Name {get;private set;}
  public string Description {get; private set;}
}

上面的 RuleAttribute 导出 IRule,还允许提供 Name 元数据。

用法如下:

[Rule("AddOneRule", "Adds one to the value")]
public class AddOneRule {
}

HTH格伦

于 2009-08-04T05:32:22.577 回答
1

您在谈论什么“属性”和“数据流”还不是很清楚,但仍然如此。

是的,通用接口总是一件好事。既然你拥有所有这些“属性”等,我建议如下:

interface IProperty
{
    string Name { get; }
    object Value { get; }
}

interface IDataStreamProvider
{
    Stream OpenStream();
}

interface IPlugin
{
    ReadOnlyCollection<IProperty> Properties { get; }

    ReadOnlyCollection<IDataStreamProvider> DataStreams { get; }
}

说到“包装器”:我不明白那些的意图。所有第三方插件都必须实现IPlugin接口,并且必须使用以下任一方式ExportAttributePluginAttribute如下所示进行装饰:

class PluginAttribute : ExportAttribute
{
    public PluginAttribute() :
        base(typeof(IPlugin))
    {
    }
}

由于可维护性问题,应尽可能避免反射。

于 2009-07-31T14:26:13.663 回答
1

我为添加这样的信息所做的是为插件创建一些自定义属性,然后在加载插件时使用 MEF 读取这些属性。您可以将任何内容添加到属性类中,例如名称、枚举、整数、其他字符串,并且非常易于使用。但要小心,新的 preview6 确实改变了一些处理方式。

[MetadataAttribute]
public class MyMetadataAttribute : Attribute
{
    public MyType MyUsage { get; set; }
}

public interface IMyMetadataView
{
    MyType MyUsage { get; }
}

public enum MyType
{
    Undefined,
    TypeOne,
    TypeTwo
}

然后在插件中你可以这样定义它......

[Export(typeof(IMyInterface))]
[MyMetadataAttribute(MyUsage = MyType.TypeOne)]
public class PluginClass: IMyInterface
{
}

您还需要将内容添加到导入中

[ImportMany(AllowRecomposition = true)]
public IEnumerable<Lazy<IMyInterface, IMyMetadataView>> plugins { get; set; }

然后,您可以直接为每个插件使用数据

var typeOnePlugin = plugins.FirstOrDefault(p => p.Metadata.MyUsage == MyType.TypeOne);

这也是使用 7 月发布的预览版 6 的方式。

于 2009-07-31T14:31:43.543 回答