开源框架 - Managed Extensibility Framework / MEF简单应用
摘要
首先,先看一下Microsoft Docs上的说明:
The Managed Extensibility Framework or MEF is a library for creating lightweight, and extensible applications. It allows application developers to discover and use extensions with no configuration required. It also lets extension developers easily encapsulate code and avoid fragile hard dependencies. MEF not only allows extensions to be reused within applications, but across applications as well.
什么意思呢?简单来说,MEF是一个框架库,开发人员可以不进行配置的方式轻松的使用它进行软件扩展开发(各种重用),而且能够减少过多的关系依赖。
MEF和Spring .Net有些类似,都是通过反射/依赖注入的方式实现IoC,但是它和Spring .Net的最大区别在于:MEF不需要在配置文件中进行配置。
例如,当有新的类库需要添加到项目中的时候,开发人员不需要重新编译整个项目,只需要将新增的类库按照之前的格式编写、编译后,把生成的DLL文件添加到项目的指定文件夹中即可。
因为MEF的AllowRecomposition参数会在项目/程序运行在有新的部件被装配成功后进行部件集的重组。这就为开发人员的开发和维护带来了极大的便利,提升开发效率。
项目实战
接下来通过一个简单的Demo来说明以下MEF框架在程序开发中的妙用。
知识点
- C#基础
- MEF基础(了解Import/ImportMany/Export含义)
- 反射
搭建框架
- 创建空白解决方案,并添加三个.Net Framwork类库(Jeremy.MEF.AnimalInterface、Jeremy.MEF.Dog、Jeremy.MEF.Kitty和Jeremy.MEF.Sheep)和一个控制台应用程序(Jeremy.MEF.Animal)
- 添加引用(Jeremy.MEF.Dog、Jeremy.MEF.Kitty和Jeremy.MEF.Sheep引用Jeremy.MEF.AnimalInterface。Jeremy.MEF.Animal引用Jeremy.MEF.AnimalInterface)。注意,控制台应用程序不需要引用除接口之外的类库!
- NuGet方式添加应用System.ComponentModel.Composition,这个类库里面封装了MEF需要用到的一些关键方法、参数等
开始编程
在Jeremy.MEF.AnimalInterface类库下分别添加接口IAnimal接口和ExportAnimalAttribute类;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Jeremy.MEF.AnimalInterface 8 { 9 /// <summary> 10 /// 动物接口 11 /// </summary> 12 public interface IAnimal 13 { 14 /// <summary> 15 /// 动物会睡觉 16 /// </summary> 17 bool CanSleep { get; set; } 18 19 /// <summary> 20 /// 展示以下其本身的特性 21 /// </summary> 22 /// <returns></returns> 23 string ShowAnimalAttribute(); 24 } 25 26 public interface IMetaData 27 { 28 /// <summary> 29 /// 动物的名字 30 /// </summary> 31 string AnimalName { get; } 32 } 33 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel.Composition; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Jeremy.MEF.AnimalInterface 9 { 10 [MetadataAttribute] 11 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 12 public class ExportAnimalAttribute : ExportAttribute 13 { 14 public ExportAnimalAttribute() : base(typeof(IAnimal)) 15 { } 16 17 /// <summary> 18 /// 动物的姓名 19 /// </summary> 20 public string AnimalName { get; set; } 21 } 22 }
在Jeremy.MEF.Dog类库下添加Dog类;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using Jeremy.MEF.AnimalInterface; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Jeremy.MEF.Dog 9 { 10 [ExportAnimal(AnimalName = "Dog")] 11 public class Dog : IAnimal 12 { 13 public bool CanSleep { get; set; } 14 15 public string ShowAnimalAttribute() 16 { 17 return "[Dog] Wolf Wolf ~~~~"; 18 } 19 } 20 }
编写Program.cs类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using Jeremy.MEF.AnimalInterface; 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 Jeremy.MEF.Animal { class Program { //其中AllowRecomposition=true参数就表示运行在有新的部件被装配成功后进行部件集的重组. [ImportMany(AllowRecomposition = true)] public IEnumerable<Lazy<IAnimal, IMetaData>> cards { get; set; } static void Main(string[] args) { Program pro = new Program(); pro.Compose(); foreach (var c in pro.cards) { //Console.WriteLine(c.GetCountInfo()); if (c.Metadata.AnimalName == "Dog") { Console.WriteLine("Here is the Doggy:"); Console.WriteLine(c.Value.ShowAnimalAttribute()); } if (c.Metadata.AnimalName == "Kitty") { Console.WriteLine("Here is the Kitty:"); Console.WriteLine(c.Value.ShowAnimalAttribute()); } if (c.Metadata.AnimalName == "Sheep") { Console.WriteLine("Here is the Sheep:"); Console.WriteLine(c.Value.ShowAnimalAttribute()); } } Console.ReadKey(); } private void Compose() { // 此处是一个目录,后续可根据需要向其中添加dll var catalog = new DirectoryCatalog("Animals"); var container = new CompositionContainer(catalog); container.ComposeParts(this); } } }
生成解决方案。手动在Program对应的Debug/Release下添加一个命名为Animals的文件夹,并将Jeremy.MEF.Dog下的Jeremy.MEF.Dog.dll复制进去。
运行效果
如下截图:
当后续有新的动物类需要加入到项目中时,只需要新增对应的类库,编程完成后把生成的dll类库复制到Animals文件夹下即可。
我这里又分别添加了Kitty类和Sheep类,代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using Jeremy.MEF.AnimalInterface; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Jeremy.MEF.Kitty 9 { 10 [ExportAnimal(AnimalName = "Kitty")] 11 public class Kitty : IAnimal 12 { 13 public bool CanSleep { get; set; } 14 15 public string ShowAnimalAttribute() 16 { 17 return "[Kitty] Miao Miao ~~"; 18 } 19 } 20 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using Jeremy.MEF.AnimalInterface; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Jeremy.MEF.Sheep 9 { 10 [ExportAnimal(AnimalName = "Sheep")] 11 public class Sheep : IAnimal 12 { 13 public bool CanSleep { get; set; } 14 15 public string ShowAnimalAttribute() 16 { 17 return "[Sheep] - Mie Mie ~~~"; 18 } 19 } 20 }
分别编译后把Jeremy.MEF.Kitty.dll和Jeremy.MEF.Sheep.dll添加到Animals文件夹下,运行Jeremy.MEF.Animal.exe,效果如下:
至此已全部完成。
源码已上传Git,欢迎下载😄
作者:Jeremy.Wu
出处:https://www.cnblogs.com/jeremywucnblog/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。