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

 
为导出附加元数据(Attaching Metadata to an Export)
 
考虑到 IMessageSender 服务更早引入。假设我们有一些实现,和相关的消费者实现(Consumer Of The Implementations)有差异。对于我们的示例,消息的传送(Transport)和是否安全(Secure)对于消费者(导入部件)都是重要的信息。
 
 
使用 ExportMetadataAttribute 特性
 
所有我们需要做的事情是使用 [System.ComponentModel.Composition.ExportMetadataAtrribute] 附加这些信息。
 
    [Export(typeof(IMessageSender))]
[ExportMetadata("transport", "smtp")]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
} [Export(typeof(IMessageSender))]
[ExportMetadata("transport", "smtp")]
[ExportMetadata("secure", null)]
public class SecureEmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
} [Export(typeof(IMessageSender))]
[ExportMetadata("transport", "phone_network")]
public class SMSSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
} public interface IMessageSender
{
void Send(string message);
}
 
 
使用自定义导出特性(Using a Custom Export Attribute)
 
为了使用比 ExportMetadata 更强类型,需要创建自定义特性并且用 [System.ComponentModel.Composition.MetadataAttribute] 标识。本例中也继承自 ExportAttribute 特性,因而创建自定义导出特性并且指定了元数据。

 
 
    [MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class MessageSenderAttribute : ExportAttribute
{
public MessageSenderAttribute() : base(typeof(IMessageSender)) { }
public MessageTransport Transport { get; set; }
public bool IsSecure { get; set; }
} public enum MessageTransport
{
Undefined,
Smtp,
PhoneNetwork,
Other
} public interface IMessageSender
{
void Send(string message);
}
 
以上,MetadataAttribute 应用于自定义导出特性。下一步是将特性应用 IMessageSender 实现:
 
    [MessageSender(Transport=MessageTransport.Smtp)]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
} [MessageSender(Transport=MessageTransport.Smtp, IsSecure=true)]
public class SecureEmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
} [MessageSender(Transport=MessageTransport.PhoneNetwork)]
public class SMSSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
}
 

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

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

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

 
 
    public class HttpServerHealthMonitor
{
[ImportMany]
public Lazy<IMessageSender, IMessageSenderCapabilities>[] Senders { get; set; } public void SendNotification()
{
Compose();
foreach (var sender in Senders)
{
if (sender.Metadata.Transport == MessageTransport.Smtp && sender.Metadata.IsSecure)
{
var messageSender = sender.Value;
messageSender.Send("Server is fine"); break;
}
}
} 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);
}
}
使用弱类型元数据(Using Weakly-Typed Metadata)
 
为了用弱类型的方式访问元数据,使用 System.Lazy<T, TMetadata> 类型传递 IDictionary<string, object> 元数据给导入。然后,可以通过 Dictionary 的元数据属性访问元数据。
 
注意:通常,我们建议通过强类型方法访问元数据,然后有些系统需要允许以动态形式访问元数据。
 
 
    public class HttpServerHealthMonitor
{
[ImportMany]
public Lazy<IMessageSender, IDictionary<string, object>>[] Senders { get; set; } public void SendNotification()
{
Compose(); foreach (var sender in Senders)
{
if (sender.Metadata.ContainsKey("Transport"))
{
var messageSender = sender.Value;
messageSender.Send("Server is fine");
}
}
} 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);
}
}

 

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

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. I.MX6 busybox set hosname and login with root

    /************************************************************************** * I.MX6 busybox set hosn ...

  2. RAID0_RAID1_RAID10_RAID5各需几块盘才可组建

    RAID 0 RAID 0即Data Stripping(数据分条技术).整个逻辑盘的数据是被分条(stripped)分布在多个物理磁盘上,可以并行读/写,提供最快的速度,但没有冗余能力.要求至少两个 ...

  3. 【转】自定义iOS的Back按钮(backBarButtonItem)和pop交互手势(interactivepopgesturerecognizer) --- 不错

    原文网址:http://blog.csdn.net/joonsheng/article/details/41362499 序 说到自定义UINavigetionController的返回按钮,iOS7 ...

  4. java中判断是否为中文

    public boolean isChinese(String strName) { char[] ch = strName.toCharArray(); for (int i = 0; i < ...

  5. Android 翻页效果 电子书

    转载请注明来自: 5进制空间-android区 相信做电子书的同学,都遇到过翻页动画的需求吧,如果你不满足与点击滑动翻页的话,这边文章应该能够帮助到你. 先上个效果图: 效果还是很不错的,不过与ibo ...

  6. 一个FragmentActivity多个Fragment的生命周期事件记录

    初次打开FragmentActivity时 VisitTaskManagerActivity(): onCreate VisitTaskManagerActivity(): onStart Visit ...

  7. JDBC中DAO事务函数模版

    DAO事物函数模版1: public void OrderFinsByPage(){ Connection conn = null; PreparedStatement pstmt = null; R ...

  8. <转>详解DNS的常用记录(下):DNS系列之三

    在上篇博文中我们介绍了DNS服务器中几种不可或缺的记录,包括A记录,NS记录和SOA记录.本篇博文中我们将继续为大家介绍DNS的另外几种常用记录,希望能对大家了解DNS有所帮助. 四 MX记录 MX记 ...

  9. Asp.net MVC 处理文件的上传下载

    如果你仅仅只有Asp.net Web Forms背景转而学习Asp.net MVC的,我想你的第一个经历或许是那些曾经让你的编程变得愉悦无比的服务端控件都驾鹤西去了.FileUpload就是其中一个, ...

  10. android开发的学习路线(转)

    第一阶段:Java面向对象编程 1.Java基本数据类型与表达式,分支循环. 2.String和StringBuffer的使用.正则表达式. 3.面向对象的抽象,封装,继承,多态,类与对象,对象初始化 ...