如何使用MEF管理相互依赖的模块?
我发现这个问题难以表达(特别是标题形式),所以请耐心等待.
我有一个应用程序,我不断修改,以做不同的事情.似乎MEF可能是管理不同功能的好方法.从广义上讲,应用程序的三个部分构成了各种管道: >收购 在它最简单的形式中,我可以将每个阶段表达为一个接口(IAcquisition等).当我想使用提供比标准数据更丰富的数据的采集组件时,问题就开始了.我想设计使用这些更丰富数据的模块,但我不能依赖它在那里. 当然,我可以将所有数据添加到接口规范中.我可以通过抛出异常或返回空值来处理较差的数据源.这似乎与理想相去甚远. 我更喜欢在三个阶段中进行MEF绑定,这样只有当模块与之前选择的模块兼容时才会向用户提供模块. 所以我的问题是:我可以指定限制可用导入集的元数据吗? 一个例子:
这可能吗?如果是这样,怎么样?
你的问题建议像这样的结构:
public class BasicData { public string Basic { get; set; } // example data } public class AdvancedData : BasicData { public string Advanced { get; set; } // example data } 现在您拥有了采集,转换和表达组件.您希望能够处理不同类型的数据,因此它们是通用的: public interface IAcquisition<out TDataKind> { TDataKind Acquire(); } public interface ITransformation<TDataKind> { TDataKind Transform(TDataKind data); } public interface IExpression<in TDataKind> { void Express(TDataKind data); } 现在你想要构建一个看起来像这样的管道: IExpression.Express(ITransformation.Transform(IAcquisition.Acquire)); 那么让我们开始构建一个管道构建器: using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.ComponentModel.Composition.Primitives; using System.Linq; using System.Linq.Expressions; // namespace ... public static class PipelineBuidler { private static readonly string AcquisitionIdentity = AttributedModelServices.GetTypeIdentity(typeof(IAcquisition<>)); private static readonly string TransformationIdentity = AttributedModelServices.GetTypeIdentity(typeof(ITransformation<>)); private static readonly string ExpressionIdentity = AttributedModelServices.GetTypeIdentity(typeof(IExpression<>)); public static Action BuildPipeline(ComposablePartCatalog catalog,Func<IEnumerable<string>,int> acquisitionSelector,int> transformationSelector,int> expressionSelector) { var container = new CompositionContainer(catalog); 该类为您的三个合约接口保存MEF类型标识.我们稍后需要那些来确定正确的出口.我们的BuildPipeline方法返回一个Action.那将是管道,所以我们可以做管道().它需要一个ComposablePartCatalog和三个Funcs(以选择导出).这样,我们可以将所有肮脏的工作保留在这个类中.然后我们从创建CompositionContainer开始. 现在我们必须构建ImportDefinitions,首先是获取组件: var aImportDef = new ImportDefinition(def => (def.ContractName == AcquisitionIdentity),null,ImportCardinality.ZeroOrMore,true,false); 此ImportDefinition只过滤掉IAcquisition的所有导出<>接口.现在我们可以把它交给容器了: var aExports = container.GetExports(aImportDef).ToArray(); aExports现在拥有所有IAcquisition<>目录中的出口.那么让我们运行选择器: var selectedAExport = aExports[acquisitionSelector(aExports.Select(export => export.Metadata["Name"] as string))]; 我们有我们的收购部分: var acquisition = selectedAExport.Value; var acquisitionDataKind = (Type)selectedAExport.Metadata["DataKind"]; 现在我们将对转换和表达式组件执行相同的操作,但略有不同:ImportDefinition将确保每个组件都可以处理前一个组件的输出. var tImportDef = new ImportDefinition(def => (def.ContractName == TransformationIdentity) && ((Type)def.Metadata["DataKind"]).IsAssignableFrom(acquisitionDataKind),false); var tExports = container.GetExports(tImportDef).ToArray(); var selectedTExport = tExports[transformationSelector(tExports.Select(export => export.Metadata["Name"] as string))]; var transformation = selectedTExport.Value; var transformationDataKind = (Type)selectedTExport.Metadata["DataKind"]; var eImportDef = new ImportDefinition(def => (def.ContractName == ExpressionIdentity) && ((Type)def.Metadata["DataKind"]).IsAssignableFrom(transformationDataKind),false); var eExports = container.GetExports(eImportDef).ToArray(); var selectedEExport = eExports[expressionSelector(eExports.Select(export => export.Metadata["Name"] as string))]; var expression = selectedEExport.Value; var expressionDataKind = (Type)selectedEExport.Metadata["DataKind"]; 现在我们可以在表达式树中将它们连接起来: var acquired = Expression.Call(Expression.Constant(acquisition),typeof(IAcquisition<>).MakeGenericType(acquisitionDataKind).GetMethod("Acquire")); var transformed = Expression.Call(Expression.Constant(transformation),typeof(ITransformation<>).MakeGenericType(transformationDataKind).GetMethod("Transform"),acquired); var expressed = Expression.Call(Expression.Constant(expression),typeof(IExpression<>).MakeGenericType(expressionDataKind).GetMethod("Express"),transformed); return Expression.Lambda<Action>(expressed).Compile(); } } 就是这样!一个简单的示例应用程序如下所示: [Export(typeof(IAcquisition<>))] [ExportMetadata("DataKind",typeof(BasicData))] [ExportMetadata("Name","Basic acquisition")] public class Acquisition1 : IAcquisition<BasicData> { public BasicData Acquire() { return new BasicData { Basic = "Acquisition1" }; } } [Export(typeof(IAcquisition<>))] [ExportMetadata("DataKind",typeof(AdvancedData))] [ExportMetadata("Name","Advanced acquisition")] public class Acquisition2 : IAcquisition<AdvancedData> { public AdvancedData Acquire() { return new AdvancedData { Advanced = "Acquisition2A",Basic = "Acquisition2B" }; } } [Export(typeof(ITransformation<>))] [ExportMetadata("DataKind","Basic transformation")] public class Transformation1 : ITransformation<BasicData> { public BasicData Transform(BasicData data) { data.Basic += " - Transformed1"; return data; } } [Export(typeof(ITransformation<>))] [ExportMetadata("DataKind","Advanced transformation")] public class Transformation2 : ITransformation<AdvancedData> { public AdvancedData Transform(AdvancedData data) { data.Basic += " - Transformed2"; data.Advanced += " - Transformed2"; return data; } } [Export(typeof(IExpression<>))] [ExportMetadata("DataKind","Basic expression")] public class Expression1 : IExpression<BasicData> { public void Express(BasicData data) { Console.WriteLine("Expression1: {0}",data.Basic); } } [Export(typeof(IExpression<>))] [ExportMetadata("DataKind","Advanced expression")] public class Expression2 : IExpression<AdvancedData> { public void Express(AdvancedData data) { Console.WriteLine("Expression2: ({0}) - ({1})",data.Basic,data.Advanced); } } class Program { static void Main(string[] args) { var pipeline = PipelineBuidler.BuildPipeline(new AssemblyCatalog(typeof(Program).Assembly),StringSelector,StringSelector); pipeline(); } static int StringSelector(IEnumerable<string> strings) { int i = 0; foreach (var item in strings) Console.WriteLine("[{0}] {1}",i++,item); return int.Parse(Console.ReadLine()); } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |