MEF初体验之四:Imports声明
组合部件使用[System.ComponentModel.Composition.ImportAttribute]特性声明导入。与导出类似,也有几种成员支持,即为字段、属性和构造器参数。同样,我们也来看下该特性类的声明:
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field
| AttributeTargets.Property, AllowMultiple=false, Inherited=false)]
public class ImportAttribute : Attribute, IAttributedImport
{ }
果然,支持这三种成员(这里Parameter而不是GenericParameter),也不支持继承,另外,与[Export]不同的是,在同一个目标上不能应用多次该特性。
属性倒入
为了向属性导入一个值,用[Import]来声明该属性。这是我们在前面的例子中使用的。例如下面倒入一个IMessageSender的代码片段:
[Import]
public IMessageSender MessageSender { get; set; }
构造函数参数
你也可以指定构造函数参数导入。这意味着你是将构造函数参数添加各自的导入,而不是将属性添加各自的导入。为了使用它,按照下面的步骤:
- 添加一个[System.ComponentModel.Composition.ImportingConstructorAttribute]特性到应该被MEF使用的构造函数上。
- 为构造函数参数添加各自的导入
例如,下面的代码在Program类构造函数上导入一个message sender。
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks; namespace ImportsDeclaring
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
Console.ReadKey();
}
void Run()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeExportedValue<IMessageSender>(new EmailSender());
var s = container.GetExportedValue<IService>();
s.Work();
}
}
[Export(typeof(IService))]
class SenderService:IService
{
private IMessageSender sender;
[ImportingConstructor]
public SenderService([Import(AllowDefault = true)]IMessageSender sender)
{
this.sender = sender;
} void IService.Work()
{
if (sender != null)
sender.Send("Hi,MEF");
}
}
interface IService
{
void Work();
}
interface IMessageSender
{
void Send(string msg);
}
class EmailSender : IMessageSender
{
public void Send(string msg)
{
Console.WriteLine("Email Sent:" + msg);
}
} }
效果如图:

参数导入
在构造函数上定义导出有这么几种不同的方式:
- 隐式导入-容器将会默认地使用参数的类型来识别契约。
- 显示导入-给参数添加[Import]特性,以此来制定要导入的契约
例如下面的两种方式等价:
[ImportingConstructor]
public SenderService(IMessageSender sender)
{
this.sender = sender;
}
[ImportingConstructor]
public SenderService([Import(typeof(IMessageSender))]IMessageSender sender)
{
this.sender = sender;
}
字段导入
MEF也支持直接将值导入到字段。形式上和属性导入很像。但是需要注意的是,私有成员(字段、属性和方法)的导入或导出仅仅支持在中/部分信任应用中,而在完全信任应用的支持上可能会有问题。
可选导入
MEF允许你指定一个可选的导入。当你启用它时,如果有可用的导出,这个容器将会提供该导出,并且设置导入为Default(T)。为了利用导入选项,在[Import]上设置AllowDefault=true。在上面我们已经使用了它,作用是当我们未执行container.ComposeExportedValue<IMessageSender>(new EmailSender()),即未给构造函数参数导入值,这时,[Import(AllowDefault=true)]相当于container.ComposeExportedValue<IMessageSender>(null),虽然参数值为null,但是契约匹配仍然生效,而如果AllowDefault=false(默认值),这时,构造器参数导入无法匹配导出,在执行下一行代码var s = container.GetExportedValue<IService>();就会报错。
导出集合
除了单个导出之外,你可以使用[ImportMany]来导出集合。这意味着指定的契约的所有实例都将被导入到这个容器。
MEF部件也支持重组。这意味着当在容器中新的导出可用时,集合会自动更新。
IPartImportsSatisfiedNotification接口
在某些场合,当MEF在处理类的实例导入过程时,该类能得到通知,对于该类来说这可能是重要的。如果是这种情况的话,请实现IPartImportsSatisfiedNotification接口,这个接口只有一个方法:OnImportsSatisfied,当所有满足部件的导入都满足时该方法将被调用。
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ImportsDeclaring
{
class Example
{
static void Main(string[] args)
{
Example e = new Example();
Notifier noter = new Notifier();
var container = new CompositionContainer();
container.ComposeParts(noter, new EmailSender(), new TcpSender(), new PhoneSender());
noter.Notify("Hi,MEF");
Console.WriteLine("-----------------");
noter.MessageSender.Send("Hi,MEF");
Console.ReadKey();
}
}
class Notifier:IPartImportsSatisfiedNotification
{
[ImportMany]
public IEnumerable<IMessageSender> Senders { get; set; }
[Import("PhoneSender")]
public IMessageSender MessageSender { get; set; }
public void Notify(string msg)
{
foreach (var item in Senders)
{
item.Send(msg);
}
} public void OnImportsSatisfied()
{
Console.WriteLine("all imports that could be satisfied have been satisfied");
}
}
[Export(typeof(IMessageSender))]
class EmailSender : IMessageSender
{
public void Send(string msg)
{
Console.WriteLine("Email Sent:" + msg);
}
}
[Export(typeof(IMessageSender))]
class TcpSender : IMessageSender
{
public void Send(string msg)
{
Console.WriteLine("TCP Sent:" + msg);
}
}
[Export("PhoneSender", typeof(IMessageSender))]
class PhoneSender : IMessageSender
{
public void Send(string msg)
{
Console.WriteLine("Phone Sent:" + msg);
}
}
}
效果如下:

MEF初体验之四:Imports声明的更多相关文章
- MEF初体验之三:Exports声明
组合部件通过[ExportAttribute]声明exports.在MEF中,有这么几种成员可声明exports的方式:组合部件(类).字段.属性和方法.我们来看下ExportAttribute类的声 ...
- MEF初体验之五:Lazy Exports
在一个部件组合中,导入将触发一个部件或者多个部件的实例化,这些部件暴露了所需原请求部件的必要的导入.对于一些应用程序来说,延迟实例化-防止图结构下的递归组合-可能对于将创建一个长久复杂的开销很大而不必 ...
- MEF初体验之二:定义组合部件和契约
组合部件 在MEF中,一个组合部件就是一个组合单元,组合部件"出口"其它组合部件需要的服务并且从其它部件"进口"需要的服务.在MEF编程模型中,为了声明组合部件 ...
- MEF初体验之一:在应用程序宿主MEF
在MEF出现以前,其实微软已经发布了一个类似的框架,叫MAF(Managed Add-in Framework),它旨在使应用程序孤立和更好的管理扩展,而MEF更关心的是可发现性.扩展性和轻便性,后者 ...
- MEF初体验之十二:Composition Batch
一个MEF容器实例是不可变的.如果catalog支持改变(像观察一个目录的改变)或是如果你的代码在运行时添加或移除部件,改变都可能发生.以前,你不得不作出改变并在组合容器上调用它的组合方法.在Prev ...
- MEF初体验之十:部件重组
一些应用程序被设计成在运行时可以动态改变.例如,一个新的扩展被下载,或者因为其它的多种多样的原因其它的扩展变得不可用.MEF处理这些多样的场景是依赖我们称作重组的功能来实现的,它可已在最初的组合后改变 ...
- MEF初体验之九:部件生命周期
理解MEF容器中部件的生命周期及其含义是非常重要的.鉴于MEF重点在开放端应用程序,这将变得尤其重要的,一旦app ships和第三方扩展开始运行,作为应用程序的开发者将很好地控制这一系列的部件.生命 ...
- MEF初体验之八:过滤目录
当在使用子容器的时候,基于某些具体标准来过滤目录可能是重要的.例如,基于部件的创建策略来过滤是很常见的.下面的代码片段演示了如何构建这种特别方法: var catalog = new Assembly ...
- MEF初体验之七:Using Catalogs
MEF特性化编程模型的价值主张之一是通过catalogs动态发现部件的能力.Catalogs允许应用程序很容易地消费那些通过[Export]已经自我注册的exports. Assembly Catal ...
随机推荐
- 左右mysql事务提交
package com.itheima.trans; import java.sql.Connection; import java.sql.PreparedStatement; import jav ...
- c#开发微信公众平台
之前帮公司开发过微信公众账号,今天特别将过程再回顾记录下来. 1.URL配置 启用开发模式需要先成为开发者,而且编辑模式和开发模式只能选择一个,进入微信公众平台-开发模式,如下: 从上面可以看出,点击 ...
- android细节之禁用activity的系统的默认切换效果
网上有非常多方法来禁用系统的默认效果,这里贴上来我觉得最简单的方法. overridePendingTransition(Animation.INFINITE, Animation.INFINITE) ...
- 使用javascript开发2048
嗯,团队队友开发了一个简单的2048...哈哈,没办法,这游戏那么疯狂,必须搞搞啦,大家能够直接粘贴代码到一个html文件,直接执行就可以 依赖文件:jquery,假设乜有,大家能够自己下载一份 &l ...
- 使用Socket沟通
当两台电脑TCP/IP协议进行通讯.平时Socket对象来表示该通信接口的两端,并通过Socket生产I/O流进行网络通信. 其中ServerSocket对象可以接收从连接的其他通信实体的请求.这个目 ...
- 勾股数组及其应用uva106
勾股数组 设三元组(a,b,c)满足a^2 + b^2 = c^2的勾股数组,那么是否存在无穷多个勾股数组呢, 答案是肯定的,将三元组乘以d,可以得到新的三元组(da,db,dc) 即(da)^2 + ...
- Storm On YARN带来的好处
1)弹性计算资源 将storm执行在yarn上后.Storm能够与其它计算框架(如mapreduce)共享整个集群的资源.这样当Storm负载骤增时,可动态为它添加计算资源. 负载减小时,能够 ...
- 分布式文件系统FastDFS介绍和配置过程
http://ylw6006.blog.51cto.com/470441/948729/ 由于网站使用nfs共享方式保存用户上传的图片,附件等资料,然后通过apache下载的方式供用户访问,在网站架构 ...
- [ios仿系列]仿支付宝手势解码
呀~.这么快就转到ios阵营了???.android还有那么多坑呢???为此我也仅仅能啃着馒头留下屈辱的眼泪了. . 本次因为开发公司产品的android版,继而ios版也负责一部分.当中一部分就是手 ...
- 最近跑hadoop遇到的一些问题
一. [#|2013-09-16T18:19:02.663+0800|INFO|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterpris ...