声明导出解释了部件导出服务的基础知识和价值观(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. python - os.path,路径相关操作

    python处理系统路径的相关操作: # -*- coding: utf-8 -*- import os # 属性 print '__file__: %s' % __file__ # 绝对路径(包含文 ...

  2. 转载RabbitMQ入门(6)--远程调用

    远程过程调用(RPC) (使用Java客户端) 在指南的第二部分,我们学习了如何使用工作队列将耗时的任务分布到多个工作者中. 但是假如我们需要调用远端计算机的函数,等待结果呢?好吧,这又是另一个故事了 ...

  3. 给IT新男的15点建议:苦逼程序员的辛酸反省与总结

    很多人表面上看着老实巴交的,实际上内心比谁都好强.自负.虚荣.甚至阴险.工作中见的多了,也就习惯了. 有一些人,什么事都写在脸上,表面上经常得罪人,甚至让人讨厌.但是他们所表现的又未必不是真性情. 我 ...

  4. php-PHP试题

    ylbtech-doc:php-PHP试题 PHP试题 1.A,PHP试题返回顶部 1.{PHP题目}标识符是变量的名称.PHP中的标识符用“$+变量名”来表示.标识符在PHP中遵循下列选项中的那些规 ...

  5. UI篇--android实现底部按钮布局

    1.采用LinearLayout布局: <LinearLayout android:id="@+id/main" android:layout_width="fil ...

  6. C语言指针5分钟教程

    指针.引用和取值 什么是指针?什么是内存地址?什么叫做指针的取值?指针是一个存储计算机内存地址的变量.在这份教程里“引用”表示计算机内存地址.从指针指向的内 存读取数据称作指针的取值.指针可以指向某些 ...

  7. mysql-5.6.15_winX64在win764位系统下的安装操作步骤总结

      mysql 版权声明:本文为博主原创文章,未经博主允许不得转载. 自从换了新电脑win764位,支持的内存从原来的3G(2G机身+1G内存条)变到了现在的8G(机身4G+4G内存条),机子的速度是 ...

  8. Unity3d 基于物理渲染Physically-Based Rendering之specular BRDF

    在实时渲染中Physically-Based Rendering(PBR)中文为基于物理的渲染它能为渲染的物体带来更真实的效果,而且能量守恒 稍微解释一下字母的意思,为对后文的理解有帮助,从右到左L为 ...

  9. hadoop 权限错误 Permission denied: user=root, access=WRITE, inode="/":hdfs:super

    关于不能执行Hadoop命令 并报权限问题执行错误1.Permission denied: user=root, access=WRITE, inode="/":hdfs:supe ...

  10. LeetCode题解——3Sum Closest

    题目: 给定一个数组,和一个指定的值,找出数组中3个数,它的和最接近这个指定值,并返回这个和. 解法: 和上一题找3个数的和为0一样,先排序再遍历,这一次不需要记录路径. 代码: class Solu ...