MEF入门.docx
- 文档编号:6451889
- 上传时间:2023-01-06
- 格式:DOCX
- 页数:23
- 大小:174.55KB
MEF入门.docx
《MEF入门.docx》由会员分享,可在线阅读,更多相关《MEF入门.docx(23页珍藏版)》请在冰豆网上搜索。
MEF入门
MEF入门
概述
MEF全称ManagedExtensibilityFramework(受管理扩展性框架),是微软.NET框架下为提高应用和组件复用程度而推出的。
使用MEF能够使静态编译的.NET应用程序转换为动态组合,这将是创建可扩展应用、可扩展框架和应用扩展的好途径。
它将做为.NETFramework4.0的组成部分之一发布。
现在,这个框架在.NET3.5中也可以运行。
解决的问题
MEF解决了什么呢?
以往,如果一个应用程序需要支持插件方式必须要实现自己的底层并且这些插件通常是针对特有应用的,不能被其他应用所使用。
实际上MEF提供了发现和组合的能力使你的应用程序可以加载扩展,为运行时的可扩展性提供了一种简单的解决方法:
MEF为宿主应用提供了一种标准的途径来暴露自身并使用外部扩展。
而扩展本身是可以被不同的应用程序所使用的。
而一个扩展依旧可以通过针对特定应用的方法来实现。
扩展之间也可以存在依赖关系,MEF则会自动将它们按照正确的顺序进行调用。
MEF还提供了一些用来定位和加载可用扩展的方法。
MEF允许使用附加元数据对扩展进行标记,从而达到易于丰富的查询和筛选的目的。
工作原理
简短说一下MEF的工作原理,MEF的核心包括一个catalog和一个CompositionContainer。
category用于发现扩展,而container用于协调创建和梳理依赖性。
每个可组合的Part提供了一个或多个Export,并且通常依赖于一个或多个外部提供的服务或Import。
每个Part管理一个实例为应用程序运行。
从这里开始
下面我们从最简单的一个例子开始:
HelloWorld!
usingSystem;
namespaceHelloWorld
{
classProgram
{
staticvoidMain(string[]args)
{
Programprogram=newProgram();
program.Run();
}
publicvoidRun()
{
Console.WriteLine("HelloWorld!
");
Console.ReadKey();
}
}
}
现在,如果不希望总是打印相同的字符串,我们应该稍微重构一下,把字符串提出来:
usingSystem;
namespaceHelloWorld
{
classProgram
{
publicstringMessage{get;set;}
staticvoidMain(string[]args)
{
Programprogram=newProgram();
program.Run();
}
publicvoidRun()
{
Console.WriteLine(Message);
Console.ReadKey();
}
}
}
下面来添加信息,并调用:
usingSystem;
namespaceHelloWorld
{
classProgram
{
publicstringMessage{get;set;}
staticvoidMain(string[]args)
{
Programprogram=newProgram();
program.Run();
}
publicvoidRun()
{
SimpleHellosimpleHello=newSimpleHello();
Message=simpleHello.Message;
Console.WriteLine(Message);
Console.ReadKey();
}
}
publicclassSimpleHello
{
publicstringMessage
{
get{return"HelloWorld!
";}
}
}
}
到这里先打住!
看上面这段代码!
这段代码已经出现了紧偶合!
现在开始!
进军MEF!
首先要添加对MEF压缩包中System.ComponetModel.Composition.dll的引用。
好了,现在我开始改造我们的代码,解掉偶合。
usingSystem;
usingSystem.ComponentModel.Composition;
namespaceHelloWorld
{
classProgram
{
[Import]
publicstringMessage{get;set;}
staticvoidMain(string[]args)
{
Programprogram=newProgram();
program.Run();
}
publicvoidRun()
{
//SimpleHellosimpleHello=newSimpleHello();
//Message=simpleHello.Message;
Console.WriteLine(Message);
Console.ReadKey();
}
}
publicclassSimpleHello
{
[Export]
publicstringMessage
{
get{return"HelloWorld!
";}
}
}
}
现在加入调用逻辑
usingSystem;
usingSystem.ComponentModel.Composition;
usingSystem.Reflection;
namespaceHelloWorld
{
classProgram
{
[Import]
publicstringMessage{get;set;}
staticvoidMain(string[]args)
{
Programprogram=newProgram();
program.Run();
}
publicvoidRun()
{
//SimpleHellosimpleHello=newSimpleHello();
//Message=simpleHello.Message;
varcatalog=newAttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
varcontainer=newCompositionContainer(catalog.CreateResolver());
container.AddPart(this);
container.Compose();
Console.WriteLine(Message);
Console.ReadKey();
}
}
publicclassSimpleHello
{
[Export]
publicstringMessage
{
get{return"HelloWorld!
";}
}
}
}
现在,程序可以正常运行了!
注意到在这个步骤中,我们做的几件事情:
i.创建了一个catalog,它将告诉MEF到什么地方去寻找Import和Export。
在这个例子中,我们告知在当前运行的程序集中。
出此之外还有很多种catalog,我们稍候会看到,当然你也可以去创建自己的catalog。
ii.创建了一个CompositionContainer,这是个高效的方式使不同的part在一起被调用。
iii.将Program的实例加入到container以便调用其依赖项。
iv.施展Compose魔法!
Message属性将在这步得到设置。
再做些更有趣的事情,我们来再添加一个信息:
usingSystem;
usingSystem.ComponentModel.Composition;
usingSystem.Reflection;
namespaceHelloWorld
{
classProgram
{
[Import]
publicstringMessage{get;set;}
staticvoidMain(string[]args)
{
Programprogram=newProgram();
program.Run();
}
publicvoidRun()
{
//SimpleHellosimpleHello=newSimpleHello();
//Message=simpleHello.Message;
varcatelog=newAttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
varcontainer=newCompositionContainer(catelog.CreateResolver());
container.AddPart(this);
container.Compose();
Console.WriteLine(Message);
Console.ReadKey();
}
}
publicclassSimpleHello
{
[Export]
publicstringMessage
{
get{return"HelloWorld!
";}
}
}
publicclassMoreMessages
{
[Export]
publicstringMessage
{
get{return"HelloAgain!
";}
}
}
}
运行!
程序竟然崩掉了!
从错误信息可以看到,有太多的Export与Import适合,MEF不知道应该使用哪个Export。
然而,事实上很幸运,你可以告诉MEF可以处理0或多个结果,你要做的只是如下修改Message属性:
usingSystem;
usingSystem.ComponentModel.Composition;
usingSystem.Reflection;
usingSystem.Collections;
usingSystem.Collections.Generic;
namespaceHelloWorld
{
classProgram
{
[Import]
publicIEnumerable
staticvoidMain(string[]args)
{
Programprogram=newProgram();
program.Run();
}
publicvoidRun()
{
//SimpleHellosimpleHello=newSimpleHello();
//Message=simpleHello.Message;
varcatelog=newAttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
varcontainer=newCompositionContainer(catelog.CreateResolver());
container.AddPart(this);
container.Compose();
foreach(varmsginMessages)
{
Console.WriteLine(msg);
}
Console.ReadKey();
}
}
publicclassSimpleHello
{
[Export]
publicstringMessage
{
get{return"HelloWorld!
";}
}
}
publicclassMoreMessages
{
[Export]
publicstringMessage
{
get{return"HelloAgain!
";}
}
}
}
WOW!
太棒了!
现在我们把这个例子变得再复杂些。
我们通常将相互没有依赖关系的组放在不同的组件中,比如在不同的应用程序集中。
为了演示MEF对此支持,我们需要添加一个新建类库项目到解决方案中。
同HelloWorld项目一样,我们需要将System.ComponetModel.Composition.dll添加到HelloWorldMessage项目的引用中。
然后我们建立下面两个类:
usingSystem;
usingSystem.ComponentModel.Composition;
namespaceHelloWorldMessage
{
publicclassMessageA
{
[Export]
publicstringMessage{get{return"HelloA!
";}}
}
}
usingSystem;
usingSystem.ComponentModel.Composition;
namespaceHelloWorldMessage
{
publicclassMessageB
{
[Export]
publicstringMessage{get{return"HelloB!
";}}
}
}
现在,我们需要做的应该是在catalog中调用这些类,所以我们需要在目录中查找相应的part。
usingSystem;
usingSystem.ComponentModel.Composition;
usingSystem.Reflection;
usingSystem.Collections;
usingSystem.Collections.Generic;
namespaceHelloWorld
{
classProgram
{
[Import]
publicIEnumerable
staticvoidMain(string[]args)
{
Programprogram=newProgram();
program.Run();
}
publicvoidRun()
{
//SimpleHellosimpleHello=newSimpleHello();
//Message=simpleHello.Message;
varcatelog=newDirectoryPartCatalog(@"..\..\..\HelloWorldMessage\bin\Debug");
//newAttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
varcontainer=newCompositionContainer(catelog.CreateResolver());
container.AddPart(this);
container.Compose();
foreach(varmsginMessages)
{
Console.WriteLine(msg);
}
Console.ReadKey();
}
}
}
注意:
DirectoryPartCatalog支持相对于AppDomain.CurrentDomain.BaseDirectory的相对路径中Part的查找。
运行!
!
!
可是我们还想要我们原来的SimpleHello和MoreMessage。
很幸运我们还有一个聚合catalog来从不同的一些资源中获取part。
usingSystem;
usingSystem.ComponentModel.Composition;
usingSystem.Reflection;
usingSystem.Collections;
usingSystem.Collections.Generic;
namespaceHelloWorld
{
classProgram
{
[Import]
publicIEnumerable
staticvoidMain(string[]args)
{
Programprogram=newProgram();
program.Run();
}
publicvoidRun()
{
//SimpleHellosimpleHello=newSimpleHello();
//Message=simpleHello.Message;
varcatalog=newAggregatingComposablePartCatalog();
catalog.Catalogs.Add(newDirectoryPartCatalog(@"..\..\..\HelloWorldMessage\bin\Debug"));
catalog.Catalogs.Add(newAttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));
varcontainer=newCompositionContainer(catalog.CreateResolver());
container.AddPart(this);
container.Compose();
foreach(varmsginMessages)
{
Console.WriteLine(msg);
}
Console.ReadKey();
}
}
publicclassSimpleHello
{
[Export]
publicstringMessage
{
get{return"HelloWorld!
";}
}
}
publicclassMoreMessages
{
[Export]
publicstringMessage
{
get{return"HelloAgain!
";}
}
}
}
现在,我们只要将我们的扩展dll拷贝到指定的目录就可以实现扩展了。
更上一层楼
你也许看到了,主程序与Console.WriteLine()之间存在紧偶合,但有时我们并不一定需要将信息输出到Console上,有时需要记录到日志中,有时需要输出到WPF中,这时我们应该如何使用MEF对此进行处理呢?
首先我们要定义一个接口来描述输出字符串的约定。
为确保正确的依赖管理我们要创建一个新的类库项目”SharedLibrary”,向其中添加此接口并将其引用到其它团队项目中。
usingSystem;
namespaceSharedLibrary
{
publicinterfaceIOutputString
{
voidOutputString(stringvalue);
}
}
回过头,我们现在来讲主程序中的Console.WriteLine()去掉了!
classProgram
{
[Import]
publicIEnumerable
[Import]
publicIOutputStringOut{get;set;}
staticvoidMain(string[]args)
{
Programprogram=newProgram();
program.Run();
}
publicvoidRun()
{
//SimpleHellosimpleHello=newSimpleHello();
//Message=simpleHello.Message;
varcatelog=newAggregatingComposablePartCatalog();
catelog.Catalogs.Add(newDirectoryPartCatalog(@"..\..\..\HelloWorldMessage\bin\Debug"));
catelog.Catalogs.Add(newAttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));
varcontainer=newCompositionContainer(catelog.CreateResolver());
container.AddPart(this);
container.Compose();
foreach(varmsginMessage)
{
Out.OutputString(msg);
}
Console.ReadKey();
}
}
在这里我们定义了Out并用Out.OutputString()替换了Console.WriteLine()。
现在,在HelloWorldMessage项目中添加下面这个类:
usingSystem;
usingSystem.Collections.Generic;
usingSharedLibrary;
usingSystem.ComponentModel.Composition;
namespaceSharedLibrary
{
[Export(typeof(IOutputString))]
publicclassOutputExt1:
IOutputString
{
publicvoidOutputString(stringvalue)
{
Console.WriteLine("Output="+value);
}
}
}
现在生成并运行主程序!
神奇吧!
下面我们再来做一个IOutputString的实现,这次我们要做的更有创造力一些。
usingSystem;
usingSystem.Linq;
usingSharedLibrary;
usingSystem.ComponentModel.Composition;
namespaceSharedLibrary
{
[Export(typeof(IOutputString))]
publicclassOutputExt2:
IOutputString
{
publicvoidOutputString(stringvalue)
{
foreach(varsinvalue.Split().Reverse())
{
Console.ForegroundColor=(ConsoleColor)(s.Length%10);
Console.Write(s+"");
}
Console.Wr
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- MEF 入门