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 ...
随机推荐
- Oracle语句集锦
创建用户并赋予dba权限 1)进入cmd 2)sqlplus / as sysdba 或者 sqlplus sys/密码 as sysdba SQL> conn sys/wcq123@orcl ...
- 在web浏览器中判断app是否安装并直接打开
最近公司App产品在运营推广上有一个需求,就是要求可以让用户在访问我们的推广网页时,就可以判断出这个用户手机上是否安装了我们的App,如果安装了则可以直接在网页上打开,否则就引导用户前往下载.从而形成 ...
- Oracle练习
--声明一个变量,并给它赋值 declare v_bonus number(8); begin select id*6 into v_bonus from A where Id=5; DBMS_OU ...
- iOS一些推荐的学习路径发展
iOS论坛里有朋友要求回答帖子,帖子的标题是: 想学IOS开发高阶一点的东西,从何開始,然后我吧啦吧啦回答写了非常多.既然敲了那么多字,我就把我写的回复也贴到博客里来分享.希望能对大家有帮助.欢迎大家 ...
- Big Event in HDU(杭电1171)(多重背包)和(母函数)两种解法
Big Event in HDU Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others ...
- QVector<QString> 显示器里面的动态数组元素QString和char *转变
QVector类是一类提供了动态数组模板. QVector<T>是Qt普通容器类的一种. 它将自己的每个对象存储在连续的内存中.能够使用索引號来高速訪问它们.QList<T>. ...
- UDE-00008 ORA-31626 ORA-06512 ORA-25254
今天在导出一个模式的时候,约140GB,出现例如以下错误: UDE-00008: operation generated ORACLE error 31626 ORA-31626: job does ...
- oracle分区表运行计划
分区表有非常多优点,以大化小,一小化了,加上并行的使用,在loap中能往往能提高几十倍甚至几百倍的效果. 当然表设计得不好也会适得其反.效果比普通表跟糟糕. 为了更好的使用分区表,这里看一下分区表的运 ...
- BackTrack5 (BT5)无线password破解教程WPA/WPA2-PSK无线password皴
昨天公布了BackTrack5 (BT5)无线weppassword破解教程之minidwep-gtk破解法一文,对BT5下破解wep无线password的简单方法做了介绍,今天奶牛为朋友们介绍下怎样 ...
- lua 远程调试 【zeroBrane 使用mobdebug】(good转)
最近基于业务需求,学习了如何使用zeroBrane这个IDE实现C/S 模式下的 lua远程调试,废话不多,上效果图: ---------------------------------------- ...