组合部件通过 [System.ComponentModel.Composition.ExportAttribute] 特性声明导出。MEF 有几种不同的方式声明导出,包括在部件层面(Part Level),通过属性(Properties)和方法(Method)声明导出。
组合部件导出(Composable Part Exports)
当组合部件需要导出自身时候使用组合部件层面导出。为了组合部件导出自身,如下例代码所示,仅仅利用 [System.ComponentModel.Composition.ExportAttribute] 特性标识组合部件。
public class SomeComposablePart { }
属性导出(Property Exports)
部件也可导出属性。属性导出的优势有几点原因。
- 允许导出密封类(Sealed Types),比如:核心 CLR 类型,或者其他三方类型。
- 允许如何创建导出中解耦。比如:导出运行时(Runtime)为你创建存在的 HttpContext。
- 允许相同的组合部件拥有继承关系的导出,比如:DefaultSendersRegistry 组合部件导出默认的一组 Sender 作为属性。
如下例:可能有一个配置类(Configuration Class)导出一个整形(Integer)的“TImeout”契约。
public class Configuration { [Export("Timeout")] public int Timeout { get { return int.Parse(ConfigurationManager.AppSettings["Timeout"]); } } } [Export] public class UsesTimeout { [Import("Timeout")] public int Timeout { get; set; } public UsesTimeout() { Compose(); } private void Compose() { //var container = new CompositionContainer(); //container.ComposeParts(this, new EmailSender()); AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var container = new CompositionContainer(catalog); container.ComposeParts(this); } }
方法导出(Method Exports)
方法导出是指部件导出其中一个方法。方法指定为导出契约,作为委托(Delegates)被导出。方法导出包括下面的许多优势。
- 允许更细力度的控制导出什么。比如:规则引擎(Rules Engine)可能导入一组可插拔(Pluggable)的方法导出。
- 规避了调用者对类型的认知情况。
- 可以通过 Light Code Gen 生成,which you cannot do with the other exports。
注意:由于框架限制,方法导出不能超出4个参数。
下面的例子中,MessageSender 类的 Send 方法作为 Action<string> 委托导出。Processor 类导入同样的委托。
public class MessageSender { [Export(typeof(Action<string>))] public void Send(string message) { Console.WriteLine(message); } } [Export] public class Processor { [Import(typeof(Action<string>))] public Action<string> MessageSender { get; set; } public void Send() { MessageSender("Processed"); } public Processor() { Compose(); } private void Compose() { //var container = new CompositionContainer(); //container.ComposeParts(this, new EmailSender()); AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var container = new CompositionContainer(catalog); container.ComposeParts(this); } }
你也可以使用简单字符约束(Simple String Contract)导出导入方法。例如:下面的“Sender”约束的使用。
public class MessageSender { [Export("MessageSender")] public void Send(string message) { Console.WriteLine(message); } } [Export] public class Processor { [Import("MessageSender")] public Action<string> MessageSender { get; set; } public void Send() { MessageSender("Processed"); } public Processor() { Compose(); } private void Compose() { //var container = new CompositionContainer(); //container.ComposeParts(this, new EmailSender()); AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var container = new CompositionContainer(catalog); container.ComposeParts(this); } }
注意:当做方法导出时,必须提供类型或者字符约束名,而不能留空。
继承导出
MEF 支持基类/接口定义导出,由实现者自动继承的能力。利用 MEF 和遗留框架集成,但是又不想修改现有的客户代码,这是理想的。System.ComponentModel.Composition.InheritedExportAttribute 特性提供这种能力。例如:ILogger 标识了继承导出的特性。Logger 实现了 ILogger,因此自动实现了 ILogger 的导出。
[InheritedExport] public interface ILogger { void Log(string message); } public class Logger : ILogger { public void Log(string message) { } }
发现非公开(Non-Public)组合部件
MEF 支持发现公开和非公开的部件。你无须为了这种用法做任何事情。请注意:在 medium/partial trust 环境(包括 Sliverlight)非公开组合将不被支持。