简要背景:
我的团队决定使用Microsoft的托管扩展性框架( MEF ),以便为我们的系统添加新的“提供者”提供可扩展的模型。
这使我们可以相对轻松地插入新的第三方提供商。
注意:我对MEF的使用和启动运行方式印象深刻。
我的问题:
由于这些提供商通常具有与之关联的不同属性,因此在运行时将这些提供程序加载到系统中时,我们需要访问提供程序数据流和属性。
由于不同的属性,为了使用所述提供程序插件,应该采取什么方法?注意到他们都做了类似的工作。
我的解决方案:
创建一个提供者必须遵守的接口,从而在每个第三方提供者周围创建一个“包装器”,从而形成一致的接口/ 与每个提供商合作的编程模型。
插件=第三方数据源(提供商)+通用接口实现。
雾化+ ve: 对于所述插件,不需要更复杂的基于反射的动态“插件”。
-ve: 必须为每个提供者编写一个包装器。 (我们需要添加MEF导出标签)
进一步说明:
对我来说,接口/包装器方法是最简单的但我被告知要研究一种基于反射的方法,可以利用反射来发现可以暴露的运行时的属性到系统。
我不赞成任何一种解决方案而不是另一种解决方案,但我有兴趣听取社区的想法(其中大多数比我更有经验)。
感谢。
答案 0 :(得分: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 格伦
答案 1 :(得分:1)
目前尚不清楚你所谈论的“属性”和“数据流”是什么,但仍然存在。
是的,通用界面总是好事。既然你拥有所有这些“属性”等,我建议如下:
interface IProperty
{
string Name { get; }
object Value { get; }
}
interface IDataStreamProvider
{
Stream OpenStream();
}
interface IPlugin
{
ReadOnlyCollection<IProperty> Properties { get; }
ReadOnlyCollection<IDataStreamProvider> DataStreams { get; }
}
说到“包装纸”:我不明白这些的意图。所有第三方插件都必须实现IPlugin
界面,并且必须使用ExportAttribute
或PluginAttribute
进行修饰,如下所示:
class PluginAttribute : ExportAttribute
{
public PluginAttribute() :
base(typeof(IPlugin))
{
}
}
由于可维护性问题,应尽可能避免反思。
答案 2 :(得分:1)
我为添加这样的信息所做的是为插件制作一些自定义属性,然后在插件加载时用MEF读取。您可以在属性类中添加任何内容,例如名称,枚举,整数,其他字符串,并且它非常易于使用。但要小心,新的预览6确实改变了一些处理方式。
[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的方式。