声明导出解释了部件导出服务的基础知识和价值观(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. POJ 2942 Knights of the Round Table (点双连通分量)

    题意:多个骑士要开会,3人及以上才能凑一桌,其中部分人已经互相讨厌,肯定不坐在同一桌的相邻位置,而且一桌只能奇数个人才能开台.给出多个人的互相讨厌图,要求多少人开不成会(注:会议不要求同时进行,一个人 ...

  2. group by的使用

    1.概述 2.原始表 3.简单Group By 4.Group By 和 Order By 5.Group By中Select指定的字段限制 6.Group By All 7.Group By与聚合函 ...

  3. HTTP请求中浏览器的缓存机制

    摘要:在Web开发过程中,我们可能会经常遇到浏览器缓存的问题.本文作者详细解释了浏览器缓存的机制,帮助读者更深层次的认识浏览器的缓存. 流程 当资源第一次被访问的时候,HTTP头部如下 (Reques ...

  4. C#中的lock关键字

    前几天与同事激烈讨论了一下,有一点收获,记录起来. 首先给出MSDN的定义: lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断.这是通过在代码块运行期间为给定对象获取互斥锁来实现的. ...

  5. python 去掉\n\t多余空格

    >>> import re >>> sss = "SELECT a.id,\n       a.customer_id as user_id,\n     ...

  6. ASP.NET CS文件中输出JavaScript脚本的3种方法以及区别

    Response.Write 与   Page.ClientScript.RegisterStartupScript 与 Page.ClientScript.RegisterClientScriptB ...

  7. 3D 矩阵旋转

    如图,需要将点(向量) v(x, y, 0) 绕 z 轴旋转角度 θ,求旋转后的点(向量) v'(x', y', 0). 大概思路: 1. 将 v(x, y, 0) 分解, v(x, y, 0) = ...

  8. webpack入门级教程

    Webpack是什么 首先可以看下官方文档,文档是最好的老师. 这里也有国外的一个朋友写的入门介绍. Webpack是由Tobias Koppers开发的一个开源前端模块构建工具.它的基本功能是将以模 ...

  9. 为什么你写的Python运行的那么慢呢?

    大约在一年前,也就是2013年在Waza(地名),Alex Gaynor提到了一个很好的话题:为什么用Python.Ruby和Javascript写的程序总是运行的很慢呢?正如他强调的,关键就是现在出 ...

  10. http响应Last-Modified和ETag(转)

    基础知识 1) 什么是”Last-Modified”? 在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时有一个Last-Modified的属性标记此文件在服务期 ...