开源框架 - 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类;

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 }

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类;

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类

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类,代码如下:

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 }

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/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· C# 13 中的新增功能实操
· Ollama本地部署大模型总结
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(4)
· langchain0.3教程:从0到1打造一个智能聊天机器人
· 用一种新的分类方法梳理设计模式的脉络