声明导出解释了部件导出服务的基础知识和价值观(Values)。有时候出于种种原因,导出关联信息是非常必要的。通常,用于解释关于功能公共契约的具体实现。允许导入满足约束要求的导出,或者导入所有可用的实现并且在导出前在运行时检查他们的功能。

 
为导出附加元数据(Attaching Metadata to an Export)
 
考虑到 IMessageSender 服务更早引入。假设我们有一些实现,和相关的消费者实现(Consumer Of The Implementations)有差异。对于我们的示例,消息的传送(Transport)和是否安全(Secure)对于消费者(导入部件)都是重要的信息。
 
 
使用 ExportMetadataAttribute 特性
 
所有我们需要做的事情是使用 [System.ComponentModel.Composition.ExportMetadataAtrribute] 附加这些信息。
 
  1. [Export(typeof(IMessageSender))]
  2. [ExportMetadata("transport", "smtp")]
  3. public class EmailSender : IMessageSender
  4. {
  5. public void Send(string message)
  6. {
  7. Console.WriteLine(message);
  8. }
  9. }
  10.  
  11. [Export(typeof(IMessageSender))]
  12. [ExportMetadata("transport", "smtp")]
  13. [ExportMetadata("secure", null)]
  14. public class SecureEmailSender : IMessageSender
  15. {
  16. public void Send(string message)
  17. {
  18. Console.WriteLine(message);
  19. }
  20. }
  21.  
  22. [Export(typeof(IMessageSender))]
  23. [ExportMetadata("transport", "phone_network")]
  24. public class SMSSender : IMessageSender
  25. {
  26. public void Send(string message)
  27. {
  28. Console.WriteLine(message);
  29. }
  30. }
  31.  
  32. public interface IMessageSender
  33. {
  34. void Send(string message);
  35. }
 
 
使用自定义导出特性(Using a Custom Export Attribute)
 
为了使用比 ExportMetadata 更强类型,需要创建自定义特性并且用 [System.ComponentModel.Composition.MetadataAttribute] 标识。本例中也继承自 ExportAttribute 特性,因而创建自定义导出特性并且指定了元数据。

 
 
  1. [MetadataAttribute]
  2. [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
  3. public class MessageSenderAttribute : ExportAttribute
  4. {
  5. public MessageSenderAttribute() : base(typeof(IMessageSender)) { }
  6. public MessageTransport Transport { get; set; }
  7. public bool IsSecure { get; set; }
  8. }
  9.  
  10. public enum MessageTransport
  11. {
  12. Undefined,
  13. Smtp,
  14. PhoneNetwork,
  15. Other
  16. }
  17.  
  18. public interface IMessageSender
  19. {
  20. void Send(string message);
  21. }
 
以上,MetadataAttribute 应用于自定义导出特性。下一步是将特性应用 IMessageSender 实现:
 
  1. [MessageSender(Transport=MessageTransport.Smtp)]
  2. public class EmailSender : IMessageSender
  3. {
  4. public void Send(string message)
  5. {
  6. Console.WriteLine(message);
  7. }
  8. }
  9.  
  10. [MessageSender(Transport=MessageTransport.Smtp, IsSecure=true)]
  11. public class SecureEmailSender : IMessageSender
  12. {
  13. public void Send(string message)
  14. {
  15. Console.WriteLine(message);
  16. }
  17. }
  18.  
  19. [MessageSender(Transport=MessageTransport.PhoneNetwork)]
  20. public class SMSSender : IMessageSender
  21. {
  22. public void Send(string message)
  23. {
  24. Console.WriteLine(message);
  25. }
  26. }
 

这就是在导出端需要做的全部事情。MEF 机制下依然会填充一个字典(Populating A Dictionary),但是这对用户不可见。

 
注意:你也可以创建没有自身导出的元数据特性,通过创建一个使用 MetadataAttribute 标识的特性。在这些情况下,元数据会被添加到有相同成员的应用自定义元数据特性的导出。
 
 
导入元数据(Importing Metadata)
 
导入部件能访问附加到导出的元数据。

 
 
使用强类型元数据(Using Strongly-typed Metadata)
 
 
为了访问强类型的元数据,通过定义匹配只读属性(名称和类型)的接口创建元数据视图。对于我们示例,像下面的接口:
 
  1. public interface IMessageSenderCapabilities
  2. {
  3. MessageTransport Transport { get; }
  4. bool IsSecure { get; }
  5. }
 
然后,就可以使用 System.Lazy<T, TMetadata> 类型开始导入,其中 T 是契约类型,TMetadata 是创建的接口。

 
 
  1. public class HttpServerHealthMonitor
  2. {
  3. [ImportMany]
  4. public Lazy<IMessageSender, IMessageSenderCapabilities>[] Senders { get; set; }
  5.  
  6. public void SendNotification()
  7. {
  8. Compose();
  9. foreach (var sender in Senders)
  10. {
  11. if (sender.Metadata.Transport == MessageTransport.Smtp && sender.Metadata.IsSecure)
  12. {
  13. var messageSender = sender.Value;
  14. messageSender.Send("Server is fine");
  15.  
  16. break;
  17. }
  18. }
  19. }
  20.  
  21. private void Compose()
  22. {
  23. //var container = new CompositionContainer();
  24. //container.ComposeParts(this, new EmailSender());
  25. AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
  26. var container = new CompositionContainer(catalog);
  27. container.ComposeParts(this);
  28. }
  29. }
使用弱类型元数据(Using Weakly-Typed Metadata)
 
为了用弱类型的方式访问元数据,使用 System.Lazy<T, TMetadata> 类型传递 IDictionary<string, object> 元数据给导入。然后,可以通过 Dictionary 的元数据属性访问元数据。
 
注意:通常,我们建议通过强类型方法访问元数据,然后有些系统需要允许以动态形式访问元数据。
 
 
  1. public class HttpServerHealthMonitor
  2. {
  3. [ImportMany]
  4. public Lazy<IMessageSender, IDictionary<string, object>>[] Senders { get; set; }
  5.  
  6. public void SendNotification()
  7. {
  8. Compose();
  9.  
  10. foreach (var sender in Senders)
  11. {
  12. if (sender.Metadata.ContainsKey("Transport"))
  13. {
  14. var messageSender = sender.Value;
  15. messageSender.Send("Server is fine");
  16. }
  17. }
  18. }
  19.  
  20. private void Compose()
  21. {
  22. //var container = new CompositionContainer();
  23. //container.ComposeParts(this, new EmailSender());
  24. AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
  25. var container = new CompositionContainer(catalog);
  26. container.ComposeParts(this);
  27. }
  28. }

 

 
元数据过滤和 DefaultValueAttribute 特性(Metadata Filtering and DefaultValueAttribute)
 
 
当指定元数据视图(Metadata View)的时候,隐式过滤将会匹配那些在视图定义中满足包含元数据属性条件的导出。你可以使用 System.ComponentModel.DefaultValueAttribute 特性指定一个元数据视图是非必要的,下面你可以看到,我们在 IsSecure 上指定默认值(Default Value)为假(False)。这意味着,如果一个部件导出 IMessageSender,但是没有提供 IsSecure 元数据,也仍将被匹配。
 
  1. public interface IMessageSenderCapabilities
  2. {
  3. MessageTransport Transport { get; }
  4. [DefaultValue(false)]
  5. bool IsSecure { get; }
  6. }
 
原文地址:

MEF 编程指南(六):导出和元数据的更多相关文章

  1. MEF 编程指南(二):定义可组合部件和契约

    可组合部件(Composable Parts)   在 MEF 内部可组合部件是一个可组合单元.可组合部件导出其他可组合部件需要的服务,并且从其他可组合部件导入服务.在 MEF 编程模型中,可组合部件 ...

  2. MEF 编程指南(九):部件生命周期

    理解 MEF 容器部件生命周期和实现是非常重要的事情.考虑到 MEF 关注可扩展应用程序.这变得尤为重要.生命期可以解释为期望部件的共享性(transitively, its exports)   共 ...

  3. MEF 编程指南(五):延迟导出

    在组合部件的时候,导入将会触发部件(部件集合)的实例化,为原始的请求部件公开必要的导出需求.对于有些应用程序,推迟实例化 - 并且防止递归组合图(Recursive Composition Down ...

  4. MEF 编程指南(三):声明导出

    组合部件通过 [System.ComponentModel.Composition.ExportAttribute] 特性声明导出.MEF 有几种不同的方式声明导出,包括在部件层面(Part Leve ...

  5. MEF 编程指南(七):使用目录

    目录(Catalogs)   MEF 特性编程模型的核心价值,拥有通过目录动态地发现部件的能力.目录允许应用程序轻松地使用那些通过 Export Attribute 注册自身的导出.下面列出 MEF ...

  6. MEF 编程指南(十二):批量组合

    MEF 容器实例并非不可变的.如果目录支持改变(像监控目录变动)或者在运行时添加/移除部件都可能发生改变.以前,你不得不做出改动并且调用 CompositionContainer 上的 Compose ...

  7. MEF 编程指南(十一):查询 CompositionContainer

    CompositionContainer 公开了一部分获取导出.导出对象以及两者集合的重载.   在这些方法重载中,你应该遵循下面的共享行为准则 - 除非特别说明.   当请求单一实例的时候,如果没发 ...

  8. MEF 编程指南(八):过滤目录

    当使用子容器的时候,基于特定的标准(Specific Criteria)过滤目录是很必要的.比如,基于部件构造策略的过滤器是很常见的.下面的代码片段演示了如何构建的特殊途径(Particular Ap ...

  9. MEF 编程指南(四):声明导入

    组合部件通过 [System.ComponentModel.Composition.ImportAttribute] 特性声明导入.类似于导出,也有几种不同的方法声明导入,即通过:字段(Fields) ...

随机推荐

  1. OK335xS 网络连接打印信息 hacking

    /*********************************************************************** * OK335xS 网络连接打印信息 hacking ...

  2. 【C#学习笔记】窗口隐藏、最小化、最大化、正常化

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  3. zoj 2027 Travelling Fee

    // 题意 : 一个人要去旅行 给你起点和终点 求最少花费 其中花费为经过路径的总费用减去该路径的中的最大花费段// 直接搜索 稍微加了个剪枝 主要是数据规模小#include <iostrea ...

  4. 【再见RMQ】NYOJ-119-士兵杀敌(三),区间内大小差值

    [题目链接:NYOJ-119] 思路:转自 点我 ,讲的挺好. #include <cstdio> #include <math.h> #define max(a,b) ((a ...

  5. 实时通讯库 libre/librem/restund/baresip

    http://www.creytiv.com/ 源码下载 libre Toolkit library for asynchronous network IO with protocol stacks ...

  6. [Everyday Mathematics]20150117

    设 $f:\bbR^{n\times n}\to\bbR$ 适合 $$\bex f(cA+B)=cf(A)+f(B),\quad f(AB)=f(BA),\quad\forall\ c\in\bbR, ...

  7. ORACLE临时表总结[转]

    临时表概念 临时表就是用来暂时保存临时数据(亦或叫中间数据)的一个数据库对象,它和普通表有些类似,然而又有很大区别.它只能存储在临时表空间,而非用户的表空间.ORACLE临时表是会话或事务级别的,只对 ...

  8. Ubuntu中使用pyUSB读取鼠标或键盘的数据程序

    参考 :http://www.orangecoat.com/how-to/read-and-decode-data-from-your-mouse-using-this-pyusb-hack 要注意的 ...

  9. ACM竞赛 Java编程小结

    1.字符串的长度 String str = new String(" abcd"); int length = str.length(); 2.数组的长度.排序 2.1对于 a[] ...

  10. homework03

    代码实现真的是大问题……在第二次作业还没有真正实现的情况下只能写这么一篇博客来整理一下从各位大神那里看到的东西. 两个弱菜加起来同样是弱菜,所以我和我的小伙伴的配合就是悲剧的聚合. 首先,大家都说C# ...