【C#进阶系列】【MEF框架(一)】

article/2025/9/15 1:46:43

C#进阶系列

第一章 【C#进阶系列】【MEF框架(一)】


文章目录

  • C#进阶系列
  • 前言
  • 一、MEF介绍
  • 二、为什么要用MEF
  • 三、MEF的概念
  • 四、使用示例
  • 五、MEF框架的好处
  • 六、源码链接
  • 总结


前言

这里对MEF作了基本的介绍,包括使用了一个特定场景(搞自动化运控上位机开发的应该更容易代入场景了),一步一步地介绍了如果从常用的编程过渡到框架性的编程开发。


一、MEF介绍

  • MEF,全称Managed Extensibility Framework(托管可扩展框架)。MEF是专门致力于解决扩展性问题的框架。
  • MSDN:Managed Extensibility Framework 或 MEF 是一个用于创建可扩展的轻型应用程序的库。 应用程序开发人员可利用该库发现并使用扩展,而无需进行配置。 扩展开发人员还可以利用该库轻松地封装代码,避免生成脆弱的硬依赖项。 通过 MEF,不仅可以在应用程序内重用扩展,还可以在应用程序之间重用扩展。
  • MEF(Managed Extensibility Framework),是轻量级的插件框架。使用简单,功能强大。
  • MEF 位于 ComponentModel.Composition 程序集中,添加 System.ComponentModel.Composition 和 System.ComponentModel.Composition.Hosting 的项目引用

二、为什么要用MEF

我们先假设一个场景:在运动控制上位机编程开发中,有固高、雷赛两种运动控制卡,现在我们需要根据实际设备使用哪种卡来实现不同的编程。
常规的实现:

class Program
{static void Main(string[] args){string ret = "";string cardName = "实际设备使用哪种运动控制卡";if (cardName == "固高板卡"){CLeadshine cLeadshine = new CLeadshine();ret = cLeadshine.InitMotionCard();ret = cLeadshine.ExitMotionCard();}else if (cardName == "雷赛板卡"){CGoogol cGoogol = new CGoogol();ret = cGoogol.InitMotionCard();ret = cGoogol.ExitMotionCard();}}
}public class CLeadshine
{public string InitMotionCard(){return "初始化固高板卡成功";}public string ExitMotionCard(){return "退出固高板卡成功";}
}public class CGoogol
{public string InitMotionCard(){return "初始化雷赛板卡成功";}public string ExitMotionCard(){return "退出雷赛板卡成功";}
}

看了上述代码,可以想象一下,里面存在一个主运行程序MEF_P1.exe、一个Leadshine.dll,一个Googol.dll,主程序需要引用两个DLL。
上述代码没有使用接口,违背了依赖倒置原则,接下来我们增加一个接口MotionCard.dll,让Leadshine.dll和Googol.dll都继承该接口,来保证使用的通用性、规范性;
代码实现如下:

class Program
{static void Main(string[] args){string ret = "";string cardName = "实际设备使用哪种运动控制卡";IMotionCard motionCard = null;if (cardName == "固高板卡"){motionCard = new CLeadshine();}else if (cardName == "雷赛板卡"){motionCard = new CGoogol();}ret = motionCard.InitMotionCard();ret = motionCard.ExitMotionCard();}
}public interface IMotionCard
{string InitMotionCard();string ExitMotionCard();
}public class CLeadshine : IMotionCard
{public string InitMotionCard(){return "初始化固高板卡成功";}public string ExitMotionCard(){return "退出固高板卡成功";}
}public class CGoogol : IMotionCard
{public string InitMotionCard(){return "初始化雷赛板卡成功";}public string ExitMotionCard(){return "退出雷赛板卡成功";}
}

可见,在使用接口后,只需要根据不同实现类实例化接口,更适用于团队的协助开发;
但仅仅是这样是不满足的,在复杂的系统设计中,不仅要考虑团队协助开发,也要想办法实现松耦合,以便日后扩展等维护;
如要团队中另外一个人新增一个正运动的板卡怎么操作?
按目前的做法是:
1.增加一个ZMotion.dll,继承IMotionCard接口,实现具体代码;
2.在主程序中,引用ZMotion.dll,增加“正运动板卡”的IF分支,并使用CZMotion实现类实例化接口;

接下来我们开始引入MEF的概念,看看MEF是如何操作的,相比较而言是否实现了松耦合,有哪些实际应用的优势。

三、MEF的概念

MEF(Managed Extensibility Framework)使开发人员能够在其.Net应用程序中提供挂钩,以供用户和第三方扩展。可以将MEF看成一个通用应用程序扩展实用工具。
MEF使开发人员能够动态创建扩展,无需扩展应用程序,也不需要任何特定于扩展内容的知识。这可以确保在编译时两者之间不存在耦合,使应用程序能够在运行时扩展,不需要重新编译。
MEF还可以在将扩展加载到应用程序之前,查看扩展程序集的元数据,这是一种速度更快的方法。
一些特定名词的说明:
Contract:契约,即一种约定
Part:部件,即契约的实现(通过Export特性加入到目录中)
Catalog:目录,存放部件的地方,当需要某个部件时,会在目录中寻找
Container:容器,存放目录并进行部件管理,如导出、导入等
Compose:组装,通过容器在目录中寻找到实现相应契约的部件,进行部件的组装
Export:导出,是部件向容器中提供的一个值,可装饰类、字段、属性或方法
Import:导入,从容器中获得可用的导出,可装饰字段、属性或构造函数参数
ImportMany:导入多个
DirectoryCatalog: 指定目录所在的路径。
Lazy<T,TMetadata>:延迟加载,由 MEF 提供来保存对导出的间接引用的类型。

四、使用示例

还是在上面的场景中修改。我们增加MEF的应用,让主程序MEF_P1.exe不依赖于Leadshine.dll和Googol.dll,而是根据ContractName(契约名称)在指定的路径中寻找DLL文件,实现相同的功能,从而解决了上层依赖下层的强耦合问题。
代码结构如下:
主程序MEF_P1.exe

class Program
{static string DllFilePath = "";static string ContractName = "";static void Main(string[] args){string ret = "";string cardName = "实际设备使用哪种运动控制卡";cardName = "固高板卡";if (cardName == "固高板卡"){DllFilePath = "Googol.dll";ContractName = "GoogolCard";}else if (cardName == "雷赛板卡"){DllFilePath = "Leadshine.dll";ContractName = "LeadshineCard";}ret = InitMotionCard();ret = ExitMotionCard();}public static string InitMotionCard(){return ExportPart(ContractName, DllFilePath).InitMotionCard();}public static string ExitMotionCard(){return ExportPart(ContractName, DllFilePath).ExitMotionCard();}public static IMotionCard ExportPart(string ContractName, string DllName){// 创建一个程序集目录,用于从一个程序集获取所有的组件定义//Assembly.GetExecutingAssembly():当前方法所在程序集//Assembly.GetCallingAssembly():调用当前方法的方法 所在的程序集//Assembly.LoadFrom(@"DLLName.dll"):DLLName.dll的程序集AssemblyCatalog Catalog = new AssemblyCatalog(Assembly.LoadFrom(DllName));//创建容器CompositionContainer Container = new CompositionContainer(Catalog);//获得容器中的ExportIMotionCard Export = Container.GetExportedValue<IMotionCard>(ContractName);return Export;}
}

接口MotionCard.dll

public interface IMotionCard
{string InitMotionCard();string ExitMotionCard();
}

插件Googol.dll

[Export("GoogolCard", typeof(IMotionCard))]
public class CGoogol : IMotionCard
{public string InitMotionCard(){return "初始化固高板卡成功";}public string ExitMotionCard(){return "退出固高板卡成功";}
}

插件Leadshine.dll

[Export("LeadshineCard", typeof(IMotionCard))]
public class CLeadshine : IMotionCard
{public string InitMotionCard(){return "初始化雷赛板卡成功";}public string ExitMotionCard(){return "退出雷赛板卡成功";}
}

这样,当需要新增一个正运动的板卡怎么操作?
1.增加一个ZMotion.dll,继承IMotionCard接口,实现具体代码;
2.在主程序中,增加“正运动板卡”的锲约名和DLL路径;
完了?还没,这时候还是需要修改主程序,还不是我们想要的,但是到了这一步,效果已经很明显了,接下来
我们把契约名和DLL名称从程序中剥离到配置文件中,并且设计可视化界面提供新增和修改就可以了
这样,当需要新增一个正运动的板卡怎么操作?
1.增加一个ZMotion.dll,继承IMotionCard接口,实现具体代码;
2.更改配置文件或者在可视化界面更改配置
这样就无需更改MEF_P1.exe的代码也无需重新编译,ZMotion.dll相当于一个插件,只通过更改配置文件即可加载到应用程序中。

最终效果如下图,当需要增加ZMotion.dll时,写好ZMotion.dll放到指定路径中,修改config.xml配置文件,增加Item3信息,然后就可以直接打开软件,软件下拉框就出现了正运动板卡了,可选中操作。
在这里插入图片描述

五、MEF框架的好处

解耦

试想下,如果主程序引用了Leadshine.dll和Googol.dll,那么就意味着你可以无限制的开放DLL中类,属性,方法的访问权限,也就意味着主程序中会出现很多耦合的代码,哪天你想移除这个DLL,程序肯定编译失败,而且你要手动删除这些耦合代码,而MEF因为是通过中间接口来完成调用的,所以只向外暴露了接口里面的成员,程序员是无法任意调用DLL中的任何方法,只能通过接口来调用。就算删掉这个DLL,程序也能正常运行!

可扩展性

举个例子,假设你的程序已经移交给客户了,哪天客户说我不想用固高、雷赛的板卡了,我要用正运动的板卡,这时,你只需重新一个ZMotion.dll,使其继承并实现IMotionCard接口,然后,只要将ZMotion.dll和改好的配置文件交给客户,并让其修改选择选项,就能运行使用正运动板卡了。是不是很方便!如果是以前,必须要修改主程序的代码,然后重新编译,发布,再将整个程序移交客户,这样说大家应该都明白了!

更多

MEF不仅可以导出类,还可以导出方法,属性,不管是私有还是公有,从而满足更多的需求!

六、源码链接

MEF插件框架学习展示(源代码)(一)

总结

依赖倒置原则:高层模板不应该依赖于底层模板,两者应该依赖于抽象,而抽象不应该依赖于细节。


http://chatgpt.dhexx.cn/article/iDrTZiED.shtml

相关文章

【虚拟化生态平台】平台架构图思路和实现细节

设计思路 我需要一个内网生态&#xff0c;通过一个nginx访问到我所有的资源&#xff0c;内部实现细节我不关心&#xff0c;那么就需要一个nginx服务器来负载所有的服务服务器太多了&#xff0c;我不想一个个的记录ip去登录&#xff0c;那我就需要一个跳板机来记录我的服务器&a…

ARM平台的虚拟化介绍

本篇博文主要介绍虚拟化的基本思想以及在arm平台如何做虚拟化&#xff0c;arm提供的硬件feature等等。 虚拟化技术简介 虚拟化技术 虚拟化是一个概念&#xff0c;单从这个概念的角度来看&#xff0c;只要是用某一种物品去模拟另一种物品都可以称为虚拟化&#xff0c;甚至于有…

ARMv8虚拟化

1 概述 2 虚拟化简介 3 AArch64虚拟化 4 Stage-2地址转换 5 指令的陷入和模拟 6 虚拟化异常 7 虚拟化通用定时器 8 虚拟化主机扩展 9 嵌套虚拟化 10 安全空间的虚拟化 11 虚拟化的成本 12 小测验 13 其它参考文章 14 接下来的计划 1 概述 本文描述了ARMv8-64的虚…

虚拟化服务器环境搭建方案,虚拟化环境建设方案

虚拟化环境建设方案 市场背景: 随着IT技术的飞速发展,基础传统IT架构模式下的应用规模扩大,需要更多的服务器来支持业务的发展,同时出现了如下几个问题: 1.资源利用率低、闲置率高,运行效率低 2.应急处理响应时间慢、服务保障差 3.运行维护成本高 虚拟化的出现很好的解决…

搭建vmware虚拟化平台的基础配置,以及Hadoop平台的搭建

需要准备的东西&#xff1a; vmware workstations centos.iso hadoop3.3.0 mobaxterm/xshell/pietty/winscp jdk的tar包 第一步 &#xff1a; 安装centos操作系统 第二步 &#xff1a; 克隆虚拟机&#xff08;也可以在hadoop安装后再克隆&#xff09; 我们这里需要选择完整克隆…

WSL2 请启用虚拟机平台 Windows 功能并确保在 BIOS 中启用虚拟化

bcdedit /set hypervisorlaunchtype autoC:\WINDOWS\system32>bcdedit /set hypervisorlaunchtype auto 操作成功完成。

嵌入式虚拟化平台jailhouse踩坑笔记

目录 简介 相关论文 架构 jailhouse的应用示例 jailhouse 官方demo jailhouse的运行 jailhouse none-root cell中挂载nfs作为根目录启动linux 注意事项 jailhouse的配置 1.cell配置文件简介 2. cell文件的生成过程 2. .c配置文件内容解析 QEMU中实现jailhouse的…

搭建华为FusionCompute虚拟化平台

最小实验要求&#xff1a;两台服务器 1、通过BMC口安装CNA操作系统 远程光驱安装CNA&#xff0c;需要设置服务器从远程光驱启动&#xff0c;然后进入BIOS可以查看BMC控制台的用户名和密码&#xff0c;以及IP&#xff0c;一般服务器都默认有。然后登陆BMC的控制台&#xff0c;进…

服务器虚拟化 涉密,面向高安全服务器虚拟化领域应用研制的安全保密虚拟化平台...

中标麒麟服务器虚拟化系统是基于中标麒麟虚拟化平台软件V7&#xff0c;面向高安全服务器虚拟化领域应用研制的安全保密虚拟化平台&#xff1b;产品通过国家保密科技测评中心基于《涉密信息系统服务器虚拟化和桌面虚拟化产品安全保密技术要求》(BMB30-2017)的安全性检测。支持海…

VA虚拟平台十大亮点

VA虚拟平台十大亮点 一、自适应多种安装环境、并可以手动调整二、兼容互联网上主流动态域名自动连接&#xff0c;并有自主的动态域名解析。三、系统稳定性有效保障和看门狗机制四、高级参数最大限度保障程序兼容性五、智能打印-动态调整、实时预览、多页排版、自动打印六、向下…

Linux虚拟化平台检测

如果要找出 Linux 系统运行在虚拟化平台中还是硬件服务器上&#xff0c;有多种方式可供大家选择&#xff0c;这主要取决于你的 hypervisor 或 container 环境。不同的虚拟化或容器技术会在其实例中引入不同的识别指纹&#xff0c;如&#xff1a;处理器厂商、特殊的 /proc 文件或…

虚拟化平台PVE(ProxmoxVirtual Environment)安装部署

PVE是一个完整的企业虚拟化开源平台。通过内置的web界面&#xff0c;可以轻松地管理虚拟机和容器、软件定义的存储和网络、高可用性集群和多个开箱即用的工具。 官方&#xff1a;Proxmox - Powerful open-source server solutions 部署前准备 1.下载镜像&#xff0c;并刻录到U…

云平台管理与部署---虚拟化平台-----KVM

第一&#xff0c;搭建KVM服务器 1&#xff0c;虚拟化平台的安装 # yum -y install qemu-kvm libvirt-daemon libvirt-client libvirt-daemon-driver-qemu # systemctl start libvirtd # ls /etc/libvirt/qemu # ls /var/lib/libvirt/images/ 第二&#xff0c;管理KVM平台 1…

云计算-华为虚拟化平台FusionCompute

目录 FusionCompute产品介绍 FusionCompute虚拟化套件 FusionCompute产品定位 FusionCompute在虚拟化套件中位置 FusionCompute产品架构 FusionCompute模块功能模块 ​编辑FusionCompute产品功能 - 虚拟化计算 FusionCompute产品功能 - 虚拟化存储 FusionCompute产品功…

服务器虚拟化如何分配内存,VMware虚拟化平台内存如何管理?

当运行一个虚拟机时,vSphere的VMKernel为虚拟机生成一段可编址的连续内存,与普通操作系统提供给上层应用使用的内存具有相同的属性特征。引入内存虚拟化之后,同样的内存地址空间,允许VMkernel同时运行多个虚拟机并保证它们之间使用内存的独立性。 虚拟化平台三种内存模式 主…

Linux部署KVM虚拟化平台

了解KVM&#xff1a; Kernel-based Virtual Machine的简称&#xff0c;是一个开源的系统虚拟化模块&#xff0c;自Linux 2.6.20之后集成在Linux的各个主要发行版本中。它使用Linux自身的调度器进行管理&#xff0c;所以相对于Xen&#xff0c;其核心源码很少。KVM已成为…

综合虚拟试衣平台

【摘要】 综合虚拟试衣平台是一个完整的虚拟试衣体验系统&#xff0c;拥有电子商城、线下虚拟试衣设备、核心SAAS平台三个模块。人们可以在线上线下&#xff0c;通过鼠标选择场景、人物、衣物自动生成试衣动画&#xff0c;或是通过摄像头摆拍实时获取。用户可通过此平台体验从…

VMware ESXi-虚拟化平台的搭建

前言&#xff1a;vSphere 是VMware公司推出一套服务器虚拟化解决方案&#xff0c;其核心组件为 VMware ESXi 和VMware vCenter&#xff0c;本文简单介绍VMware ESXi 的安装使用。 它与我们常用的虚拟机不同的是&#xff0c;日常使用的虚拟机是需要依赖于一个操作系统的&#xf…

虚拟仿真实验平台服务器需求,虚拟仿真实验中心平台建设方案.pptx

虚拟仿真实验中心平台建设方案.pptx 一,二,三,虚拟仿真实验概述,虚拟仿真实验教学,虚拟仿真实验中心建设,一,二,三,虚拟仿真实验概述,虚拟仿真实验教学,虚拟仿真实验中心建设,,随着计算机、互联网等先进技术的迅速发展和大面积普及推广,虚拟仿真实验应运而生。虚拟仿真实验改变…

服务器虚拟化和云平台,云平台和服务器虚拟化区别

云平台和服务器虚拟化区别 内容精选 换一换 云硬盘(Elastic Volume Service, EVS)可以为云服务器提供高可靠、高性能、规格丰富并且可弹性扩展的块存储服务,可满足不同场景的业务需求,适用于分布式文件系统、开发测试、数据仓库以及高性能计算等场景。云服务器包括弹性云服务…