您好,欢迎访问三七文档
插件式程序开发12/30/2019目录MAF托管插件框架1MEF拓展可扩展性框架2提起插件式312/30/2019MAF托管插件框架12/30/2019(不适用)MAF托管插件框架MAF是一个复杂的框架,并且即使是对于简单的应用程序,设置插件管道也很繁琐。它比MEF复杂,需要配置很多元素。但它也有些优点:1.宿主程序和插件程序可以进行隔离,以此降低运行插件所带来的风险;2。MAF的设计是基于7个程序集组成的管道,这些管道部分可以单独更换。12/30/2019宿主宿主视图宿主适配器协定插件适配器插件视图插件MEF拓展可扩展性框架12/30/2019(适用)MEF拓展可扩展性框架MEF(ManagedExtensibilityFramework),是微软推出的一款用于搭建可扩展应用程序的框架,起初是独立于.Net发布的,后来集成到了.Net4.0中。使用该框架可以非常轻松地扩展一个已发布的应用程序的功能,连VisualStudioIDE中的代码编辑器窗口也采用了MEF的思想,因此大大方便了开发人员对编辑器的扩展。MEF可用在任何使用.NETFramework的地方。可以在客户端应用程序中使用MEF(无论应用程序使用的是Windows窗体、WPF,还是任何其他技术),也可以在使用ASP.NET的服务器应用程序中使用MEF。12/30/2019MEF的关键概念导入,这里建议作为一个名词来理解,即一个接受者,它可以接受外来的东西。就好比是下图中的盒子,它可以接受其它积木。12/30/2019ImportMEF的关键概念导出,同样建议以一个名词来理解,即一个第三方的产物。它就像上图中不同颜色的积木,这些积木不属于这个盒子,但是能被放入盒子中,来丰富盒子的功能。12/30/2019ExportMEF的关键概念协议。要想使盒子能接受积木(比如,圆柱体只能放入圆形的接口中),那这些积木必须符合一定的形状。而这些形状就相当于是应用程序和第三方扩展之间的一个协议。12/30/2019ContractMEF的关键概念组合(动词),即将多个符合协议要求的部件组合在一起,构成一个功能丰富的应用程序。就好比是将不同形状的积木,按照接口的形状组合在一起。12/30/2019Compose它是如何工作的?MEF会动态查找用户所指定的目录,如果发现该目录中的程序集满足协议要求,就会启动自身的组合引擎,然后根据不同的协议约定把这些扩展导入到应用程序内部。12/30/2019Plugindir用MEF实现一个最简单的可扩展应用程序12/30/2019这个和普通定义接口没什么两样。协议有了协议之后,就需要给应用程序安一个接受者。让这个应用程序可以通过接受者来获取第三方扩展。MEF提供了[Import]和[ImportMany]两种attribute。区别就是Import只能接受符合协议的一个扩展,而ImportMany可以接受多个,并把多个扩展放入集合中。安装接受者这个产物的生产过程其实就是实现接口的过程,唯一的区别是我们要为这个实现打上个标签,从而告诉我们的组合引擎这个东西是给接受者的。MEF提供了Export来暗示这是一个可以提供给接受者的产物。符合协议的产物注:添加System.ComponentModel.Composition程序集到项目中。用MEF实现一个最简单的可扩展应用程序12/30/2019代码会自动去发现扩展,然后加入到应用程序中来。要做的只是把新扩展的程序集放入执行目录下的plugin目录中就可以了发动引擎示例代码namespaceCore{publicinterfaceIPlugin{stringText{get;}voidDo();}}12/30/2019协议接口IPlugin示例代码[ImportMany]publicIEnumerableIPluginplugins;privatevoidForm1_Load(objectsender,EventArgse){foreach(IPluginplugininplugins){Buttonbtn=newButton{Text=plugin.Text};btn.Click+=(s,arg)={plugin.Do();};btn.Width=100;this.panel1.Controls.Add(btn);}}12/30/2019安装接收器示例代码namespacePluginInstance{[Export(typeof(IPlugin))]publicclassMyPlugin:IPlugin{publicstringText{get{returnThisisademo;}}publicvoidDo(){MessageBox.Show(Text);}}}12/30/2019符合协议的产物MyPlugin示例代码privateCompositionContainer_container;privatevoidInit(){varcatalog=newAggregateCatalog();stringpath=Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)+@\plugin\;catalog.Catalogs.Add(newDirectoryCatalog(path,*.dll));_container=newCompositionContainer(catalog);try{this._container.ComposeParts(this);}catch(CompositionExceptioncompositionException){Console.WriteLine(compositionException.ToString());}}12/30/2019发动引擎补充一12/30/2019更新:DirectoryCatalog只能加载一个文件夹,且不能递归加载子孙目录,如果希望加载子目录,需要自己写代码添加:stringpath=Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)+@\plugin\;foreach(stringdiinDirectory.EnumerateDirectories(path)){catalog.Catalogs.Add(newDirectoryCatalog(di));}补充二12/30/2019更新:DirectoryCatalog默认只加载*.dll类型文件,如果希望加载其它类型文件,可以这样:////从exe中获取Partscatalog.Catalogs.Add(newDirectoryCatalog(path,*.exe));////从dll中获取Partscatalog.Catalogs.Add(newDirectoryCatalog(path,*.dll));运行界面12/30/2019MEFDEMO程序总结12/30/2019在工程内部添加对接口的引用,插件dll或者插件exe按照协议约定方式进行实现提起插件式12/30/2019(适用)提起插件式这样的主程序不需要改动。需要插件时,拿来就能用,插件更新时,也只需更新这个插件即可。需要判断的只是插件dll是否由预定义的插件接口实现,如果有则认为该类适配于主程序(是主程序的插件)主程序不添加对接口的引用,也不应该在客户端实例化插件对象,因为插件开发的初衷是为了以后更新的时候不更改主程序,只提供对应的dll下载,就可以直接使用了,以前的接口都定义好了,新的实现类也就是不可预料的,因此不在主程序实例化实现接口的类。12/30/2019提起插件式协议接口IMsgnamespaceIMsg{publicinterfaceIMsgPlug{voidOnShowDlg();}}12/30/2019提起插件式符合协议产物MyPlugin...publicvoidOnShowDlg(){InitializeComponent();this.ShowDialog();}...12/30/2019提起插件式加载插件string[]files=Directory.GetFiles(Directory.GetCurrentDirectory()+@\Plugins);foreach(stringfileinfiles){if(file.ToUpper().EndsWith(.DLL)){try{Assemblyab=Assembly.LoadFrom(file);//载入dllType[]types=ab.GetTypes();foreach(Typetintypes){if(t.GetInterface(IMsgPlug)!=null){plugins.Add(ab.CreateInstance(t.FullName));listbox1.Items.Add(t.FullName);}}}catch(Exceptionex){MessageBox.Show(ex.Message);}}12/30/2019提起插件式使用插件try{if(this.listbox1.SelectedIndex==-1)return;objectselObj=this.plugins[this.listbox1.SelectedIndex];Typet=selObj.GetType();MethodInfoOnShowDlg=t.GetMethod(OnShowDlg);if(OnShowDlg!=null){OnShowDlg.Invoke(selObj,null);}MethodInfoOnShowInfo=t.GetMethod(OnShowInfo);if(OnShowInfo!=null){objectreturnValue=OnShowInfo.Invoke(selObj,null);this.lable1.Content=returnValue.ToString();}}catch{}12/30/2019运行界面12/30/2019MEF和提起插件式异同12/30/2019MEF:工程内部添加对接口的引用提起插件式:主程序不添加对接口的引用不需要Import,Export标记都自动遍历程序启动目录下plugin目录中符合协议的插件dllTHEEND12/30/2019
本文标题:插件式程序开发.
链接地址:https://www.777doc.com/doc-2379823 .html