麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

[連載]《C#通訊(串口和網(wǎng)絡(luò))框架的設(shè)計與實現(xiàn)》-9.插件引擎設(shè)計

2019-11-14 13:42:35
字體:
供稿:網(wǎng)友

目       錄

第九章           插件引擎設(shè)計... 2

9.1           框架的契約-接口... 2

9.2           插件的雛形-抽象類... 3

9.3           實現(xiàn)接口... 4

9.4           反射機制... 5

9.5           反射工具類... 8

9.6           小結(jié)... 9

 

第九章     插件引擎設(shè)計

在介紹《第10章 宿主程序詳細(xì)設(shè)計》之前對接口和插件的相關(guān)內(nèi)容進(jìn)行一下整體介紹,在設(shè)計宿主程序的時候會用到這些知識,也是宿主程序與插件之間交互的核心內(nèi)容。

9.1    框架的契約-接口

     插件式框架的宿主程序啟動后,它首先會加載相應(yīng)的配置文件(例如:設(shè)備驅(qū)動配置文件等),找到相應(yīng)的插件程序集,這些程序集以DLL文件格式存在,框架的宿主程序會找到指定的插件類型,由插件引擎依據(jù)插件類型(例如:IRunDevice)生成對象實例,由框架的宿主程序的管理器對插件實例進(jìn)行管理和調(diào)度。

    一個插件程序集可能包括多個插件類型,那么框架宿主程序是如何識別這些類型是否為要加載的插件呢?每個插件對象都有一個身份標(biāo)識-接口,這個標(biāo)識在框架設(shè)計中被稱為“通訊契約”。接口可以被看作是一種定義了必要的方法、屬性和事件的集合,因此宿主程序就可以通過這種契約來生成具體的實例對象,并對其他組件或接口公開可操作的對象。

    插件式框架作為一個高聚合低耦合的平臺,它的功能定義與功能實現(xiàn)之間是分離的。只要符合插件規(guī)范的二次開發(fā)組件都可以掛載到框架平臺中,而它并不并心這些組件的具體功能。當(dāng)然,框架平臺提供了一些必要的信息、機制來保證這些組件能夠正常實現(xiàn)二次開發(fā)的功能。

    在具有多個邏輯層次的結(jié)構(gòu)設(shè)計中,各層之間的通信大多通過接口來實現(xiàn),接口不會輕易改變,如果一個層的功能發(fā)生變化,不會影響其他層;只要正常實現(xiàn)了接口的組件功能,那么程序的運行就沒有問題。這種做法使得各層之間的相互影響降低到最低,總之,接口在多業(yè)務(wù)層級中能夠更好的解耦。

    在大部分功能性的編程和設(shè)計工作中,很少需要考慮“接口(interface) ”的情況,如果我們僅僅滿足通過控件的方式在IDE上編程和使用.NET Framework中一般的類庫,可能永遠(yuǎn)不會在程序中使用到接口,即使在C#等面向?qū)ο笳Z言的語法書中讀者會無數(shù)次看到過這個詞,也只是完成一般性的功能,并未掌握面向?qū)ο缶幊痰暮诵乃枷搿?/p>

     接口是一般行為的定義和契約。如貓和狗等動物,只需要將一般性的、公共性的屬性、動作等定義在接口里,例如:有眼睛、可以吃東西等。盡管不同動物之間存在很大差異,但是接口并不考慮它們各自的特性或功能的差異,例如:什么顏色的眼睛、吃什么東西等。它只關(guān)心這些類型都必須實現(xiàn)接口定義的所有功能,而實現(xiàn)了這個接口就可以被看作是一種動物。

    因此,接口的兩個主要的作用是:

n  定義多個類型都需要的公共方法、屬性。

n  作為一種不可實例化的類型存在。

繼承接口實現(xiàn)定義的方法、屬性等,實際上是實現(xiàn)了一種策略。

9.2    插件的雛形-抽象類

接口與抽象類非常相似,例如兩者都不能new一個實例對象,卻都可以作

為一種契約和定義被使用。但是接口和抽象類有本質(zhì)的不同,這些不同包括:

n  接口沒有任何實現(xiàn)部分,但是抽象類可以繼承接口后部分實現(xiàn)代碼。

n  接口沒有字段,但是抽象類可以包含字段。

n  接口可以被結(jié)構(gòu)(Struct)繼承,但是抽象類不行。

n  抽象類有構(gòu)造函數(shù)和析構(gòu)函數(shù)。

n  接口僅能繼承自接口,而抽象類可以繼承自其他類和接口。

n  接口支持多繼承,抽象類僅支持單根繼承。

在MSDN的相關(guān)內(nèi)容中,給出了如下關(guān)于接口與抽象類的建議:

n  如果預(yù)計要創(chuàng)建組件的多個版本,則創(chuàng)建抽象類。抽象類提供簡單易行的方法來控制組件版本。通過更新基類,所有繼承類都隨更改自動更新。另一方面,接口一旦創(chuàng)建就不能更改,如果要更新接口的版本,必須創(chuàng)建一個全新的接口。

n  如果創(chuàng)建的功能將在大范圍的全異對象間使用,則使用接口。抽象類應(yīng)主要用于關(guān)系密切的對象,而接口最適合為不相關(guān)的類提供通用的功能。

n  如果要設(shè)計小而簡練的功能模塊,應(yīng)該使用接口。如果要設(shè)計大的功能單元,則應(yīng)該使用抽象類。

n  如果要在組件的所有實現(xiàn)間提供通用的已實現(xiàn)功能,應(yīng)該使用抽象類。抽象類允許部分實現(xiàn)類,而接口不包含任何成員的實現(xiàn)。

9.3    實現(xiàn)接口

接口和抽象類都可以作為“通信契約”,為子類提供規(guī)范。下面定義一個接口和抽象類。

//定義一個接口public interface IMyInterface{       void Action(int type);       string Method(int para);}//定義一個抽象類public abstract class BaseAbstract:IMyInterface{       public abstract void Action(int type); //繼承此類抽象類時必須實現(xiàn)這個方法。       public string Method(int para)         //實現(xiàn)這個方法       {              return para.ToString();       }}

繼承接口的話,需要實現(xiàn)全部定義的方法或?qū)傩裕缦麓a:

public class MyClass1:IMyInterface{       public void Action(int type)       {              Console.WriteLine(type.ToString());       }             public string Method(int para)               {              return para.ToString();       }}

繼承抽象類的話,只需要實現(xiàn)抽象類沒有實現(xiàn)的方法或?qū)傩裕话銥槌橄蠓椒ɑ驅(qū)傩裕缦麓a:

public class MyClass2:BaseAbstract{       public void Action(int type)   //繼承抽象類,只需要實現(xiàn)這個函數(shù)。       {              Console.WriteLine(type.ToString());       }}

9.4    反射機制

    有了設(shè)備驅(qū)動或插件,還不能掛載到框架平臺的宿主程序中。我們考慮的問題是:已經(jīng)有了任意多個類型插件程序集,框架平臺如何從程序集中根據(jù)類型定義在內(nèi)存中生成插件對象?

   回顧普通情況下程序引用其他程序集組件的過程。首先,需要使用“添加引用”對話框加載程序集。然后,通過using關(guān)鍵字引用命名空間。最后,在命令空間下找到相應(yīng)的類,并new出來一個實例。這是一種靜態(tài)加載程序集的方式。

   在插件式應(yīng)用框架中,這種方法并不適合。宿主程序在編譯時并不知道它將要處理哪些程序集,更沒有辦法靜態(tài)的將插件類型通過using關(guān)鍵字引入,這些都是在運行時才能獲得的信息。在這樣的情況下,也無法使用靜態(tài)方法和new關(guān)鍵字來生成一個類型實例。而是需要在運行時獲得相關(guān)信息動態(tài)加載程序集,這個過程被稱為反射。

   反射是動態(tài)發(fā)現(xiàn)類型信息的一種能力,它類似后期綁定,幫助開發(fā)人員在程序運行時利用程序集信息動態(tài)使用類型,這些信息在編譯時是未知的,反射還支持更高級的行為,如能在運行時動態(tài)創(chuàng)建新類型,并調(diào)用這些類型的方法等。

    JIT編譯器在將IL代碼編譯成本地代碼時,會查看IL代碼中引用了那些類型。在運行時,JIT編譯器利用程序集的TypeRef和AssemblyRef元數(shù)據(jù)表的記錄項來確定哪一個程序集定義了引用的類型。在 AssemblyRef元數(shù)據(jù)記錄項中記錄了程序集強名稱的各個部分—包括名稱,版本,公鑰標(biāo)記和語言文化。這四個部分組成了一個字符串標(biāo)識。JIT編譯 器嘗試將與這個標(biāo)識匹配的程序集加載到當(dāng)前的AppDomain中。如果程序集是弱命名的,標(biāo)識中將只包含名稱。

   .NET Framework中,為了實現(xiàn)動態(tài)加載,需要熟悉Assembly、Type和Activator等工具類的方法。框架平臺主要使用了Assembly工具類,這個類中包括Load、LoadFrom和LoadFile。

1.      Assembly的Load方法

   在內(nèi)部CLR使用Assembly的Load方法來加載這個程序集,這個方法與Win32的LoadLibray等價。在內(nèi)部,Load導(dǎo)致CLR對程序集應(yīng)用一個版本重定向策略。并在GAC中查找程序集,如果沒有找到,就去應(yīng)用程序的基目錄,私有路徑目錄和codebase指定的位置查找。如果是一個弱命名程序集,Load不會向程序集應(yīng)用重定向策略,也不會去GAC中查找程序集。如果找到將返回一個Assembly的引用,如果沒有找到則拋出FileNotFoundException異常。注意:Load方法如果已經(jīng)加載一個相同標(biāo)識的程序集只會簡單的返回這個程序集的引用,而不會去創(chuàng)建一個新的程序集。

大多數(shù)動態(tài)可擴展應(yīng)用程序中,Assembly的Load方法是程序集加載到AppDomain的首選方式。這種方式需要指定程序集的標(biāo)識字符串。對于弱命名程序集只用指定一個名字。

2.Assembly的LoadFrom方法

    當(dāng)我們知道程序集的路徑的場合,可以使用LoadFrom方法,它允許傳入一個Path字符串,在內(nèi)部,LoadFrom首先調(diào)用AssemblyName的靜態(tài)方法GetAssemblyName。這個方法打開指定的文件,通過AssemblyRef元數(shù)據(jù)表提取程序集的標(biāo)識,然后關(guān)閉文件。隨后,LoadFrom在內(nèi)部調(diào)用Assembly的Load方法查找程序集。到這里,他的行為和Load方法是一致的。唯一不同的是,如果按Load的方式?jīng)]有找到程序集,LoadFrom會加載Path路徑指定的程序集。另外,Path可以是URL。

3.Assembly的LoadFile方法

    這個方法初一看和LoadFrom方法很像。但LoadFile方法不會在內(nèi)部調(diào)用Assembly的Load方法。它只會加載指定Path的程序集,并且這個方法可以從任意路徑加載程序集,同一程序集如果在不同的路徑下,它允許被多次加載,等于多個同名的程序集加載到了AppDomain中,這一點和上面的兩個方法完全不一樣。但是,LoadFile并不會加載程序集的依賴項,也就是不會加載程序集引用的其他程序集,這會導(dǎo)致運行時找不到其他參照DLL的異常。要解決這個問題,需要向AppDomain的AssemblyResolve事件登記,在回調(diào)方法中顯示加載引用的程序集。類似于這樣:

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args){       if (args.Name != null)       {              return Assembly.LoadFrom(string.Format("{0}//plugin//{1}.dll", application.StartupPath, new AssemblyName(args.Name).Name));       }       return null;}

      特別注意:要測試LoadFile有沒有加載引用的DLL,切不可將DLL拷貝到應(yīng)用程序的根目錄下測試,因為該目錄是CLR加載程序集的默認(rèn)目錄,在這個目錄中如果存在引用的DLL,它會被加載,造成LoadFile會加載引用DLL的假象。可以在根目錄下新建一個子目錄如plugin,把引用的dll拷貝到這里面進(jìn)行測試。

     反射機制也有它的缺點:安全性和性能方面。但是,框架平臺在啟動的時候、以及增加新設(shè)備驅(qū)動(插件)的時候需要使用反射,一旦加載到宿主程序中,與靜態(tài)引用程序集沒有本質(zhì)區(qū)別,都是寄存在內(nèi)存中。

9.5    反射工具類

插件式框架平臺使用反射掛載設(shè)備驅(qū)動,在宿主程序中運行,需要一個專用的工具類來完成相關(guān)功能。代碼定義如下:

/// <summary>/// 一個輕便的 IObjectBuilder 實現(xiàn)/// </summary>public class TypeCreator : IObjectBuilder{       public T BuildUp<T>() where T : new()       {              return Activator.CreateInstance<T>();       }       public T BuildUp<T>(string typeName)       {              return (T)Activator.CreateInstance(Type.GetType(typeName));       }       public T BuildUp<T>(object[] args)       {              object result = Activator.CreateInstance(typeof(T),args);              return (T)result;       }       /// <summary>       /// 框架平臺主要使用了這個函數(shù)。       /// </summary>       /// <typeparam name="T"></typeparam>       /// <param name="assemblyname"></param>       /// <param name="instancename"></param>       /// <returns></returns>       public T BuildUp<T>(string assemblyname, string instancename)       {              if (!System.IO.File.Exists(assemblyname))              {                     throw new FileNotFoundException(assemblyname + " 不存在");              }              System.Reflection.Assembly assmble = System.Reflection.Assembly.LoadFrom (assemblyname);              object tmpobj = assmble.CreateInstance(instancename);              return (T)tmpobj;       }       public T BuildUp<T>(string typeName, object[] args)       {              object result = Activator.CreateInstance(Type.GetType(typeName), args);              return (T)result;       }}

9.6    小結(jié)

    下一章節(jié)介紹宿主程序詳細(xì)設(shè)計,需要對反射機制有一定的了解,并且會使用到上面的工具類,并在此基礎(chǔ)上進(jìn)行擴展。

    框架平臺就要完全了,只需要一小步了。

 

作者:唯笑志在

Email:504547114@QQ.com

QQ:504547114

.NET開發(fā)技術(shù)聯(lián)盟:54256083

文檔下載:http://pan.baidu.com/s/1pJ7lZWf

官方網(wǎng)址:http://www.bmpj.net


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 亚洲av一级毛片特黄大片 | 成品片a免费直接观看 | 久久国产秒 | 最新中文字幕日本 | 久久精品国产一区二区电影 | 国产无限资源在线观看 | 国产一区精品视频 | 婷婷亚洲一区二区三区 | 宅男噜噜噜66国产免费观看 | 免费高潮在线国 | 青青操国产 | 成人免费福利网站 | 91精品观看91久久久久久国产 | 亚洲二区免费 | 精精国产xxxx视频在线播放7 | 在线a毛片免费视频观看 | 精品久久久久久国产三级 | 999久久国精品免费观看网站 | 黄色成人小视频 | 91久久国产综合久久91猫猫 | 九九热久久免费视频 | 美女视频黄视大全视频免费网址 | 国产成人自拍av | 免费a级毛片大学生免费观看 | 性欧美xxxx免费岛国不卡电影 | 大西瓜永久免费av在线 | 中文字幕在线不卡视频 | 日韩视频不卡 | 国产精品成人久久久久a级 欧美特黄一级高清免费的香蕉 | 国产老师做www爽爽爽视频 | 97伦理| 国产一级毛片在线看 | 亚洲一区二区网址 | 久久国产免费视频 | 欧美日韩一区,二区,三区,久久精品 | 精品中文字幕在线观看 | 免费人成年短视频在线观看网站 | chengrenzaixian| 国产精品一区在线免费观看 | 国产精品成人一区二区三区电影毛片 | 亚洲视频综合网 |