接口映射的实现及原理
可以看出,每一個“方法()”,實際上都是不同的。
在“有接口的繼承”中,接口將“Test.接口.方法()”進行了重新映射。這個映射是如何完成的呢?
看看如下的IL代碼:
在采取使用它們自己的類作為訪問入口時,代碼實現如下:
沒有接口的繼承,它實現的方式如下:
| void 方法() {1L_0000: ldstr L_0005: call void [mscorlib]System.Console::WriteLine(string)L_000a: ret } |
而有接口的繼承,實現方式是這樣的:
| void Test.接口.方法() {Test.接口::方法1L_0000: ldstr L_0005: call void [mscorlib]System.Console::WriteLine(string)L_000a: ret } |
在這里可以看出,有接口的繼承實際上對“方法”進行override,但這個override是覆蓋的接口的方法的實現成員,并非是類的方法成員。
然后,我們繼續看看在客戶類中對兩者進行調用的IL
沒有接口繼承的IL
????? L_001d: newobj instance void Test.沒有接口的繼承::.ctor() //創建實例
????? L_0022: stloc.2
????? L_0023: ldloc.2?
????? L_0024: callvirt instance void Test.沒有接口的繼承::方法()
有接口繼承的IL
????? L_003a: newobj instance void Test.有接口的繼承::.ctor() //創建實例
????? L_003f: stloc.s 有接口的繼承1
????? L_0041: ldloc.s 有接口的繼承1
????? L_0043: callvirt instance void Test.基類::方法()
如果是采取接口訪問時,則狀況如下:
沒有接口繼承的IL
????? L_0029: newobj instance void Test.沒有接口的繼承::.ctor()
????? L_002e: stloc.3
????? L_002f: ldloc.3??
????? L_0030: callvirt instance void Test.接口::方法()
有接口繼承的IL
????? L_0048: newobj instance void Test.有接口的繼承::.ctor()
????? L_004d: stloc.s 接口3
????? L_004f: ldloc.s 接口3
????? L_0051: callvirt instance void Test.接口::方法()
----------------------------------------------------------------------------
?????? 注意一下上面標記顏色的部分,可以看出,采用不同的訪問方式,實現的結果并不盡相同。也就是說,針對接口實現了的方法,與類本身自帶的實現,是兩回事,這種情況很類似于采用new關鍵字進行創建一個新的同名成員方法時遭遇的問題。
????? 結果之所以會不同,是由于訪問的方式不同的原因,如果采用“基類”來訪問,很明顯,這里獲得的就是基類的成員實現。也就是說,這也是多態的一種體現,但并非不可預知或不可控制的。
看見有人說VB很難實現接口的映射,實際上并不是這樣,要解釋一下這個問題,這里不得不說一下,強類型的C#語法的含義。
????? “基類?objBase = new?基類();” 這種語法,表示的是使用“基類”來訪問新建的“基類”的實例,換而言之,“基類 objDevired = new?沒有接口的繼承();”表示的就是使用基類來訪問新建的“沒有接口的繼承”的實例。
接口的訪問,也是如此,在原理上,將接口看作是一個十分特殊的抽象類,它與一般的抽象類的區別在于強制了成員的實現(接口的語法由編譯器來驗證的,在CLR并未提供限制性機制),所以,在有一些設計模式中,也可以看到采用了接口-抽象類-具體類的方式來繞開這類強制成員實現的檢查,從而提高靈活性。
????? 所以,VB.NET照樣也可以完成接口映射,因為接口本身的實現機制仍舊是依賴于類的基本特征的。
????? 示例偽代碼如下:?????
??????'?Methods
??????Sub?方法()Sub?方法()
End?Interface
Friend?Class?基類Class?基類
??????Implements?接口
??????Public?Sub?New()Sub?New()
??????Private?Sub?Test()Sub?Test.接口.方法()?Implements?接口.方法
??????Public?Sub?方法()Sub?方法()
End?Class
Friend?Class?沒有接口的繼承Class?沒有接口的繼承
??????Inherits?基類
??????Public?Sub?New()Sub?New()
??????Public?Sub?方法()Sub?方法()
End?Class
?
Friend?Class?有接口的繼承Class?有接口的繼承
??????Inherits?基類
??????Implements?接口
??????Public?Sub?New()Sub?New()
??????Private?Sub?Test()Sub?Test.接口.方法()?Implements?接口.方法
End?Class
但就接口本身來說,是一個便利性的工具,在編程時的認識上,我們不應該將它與類視作“同一類東西”,它是對類的之間關系的一個描述。對于類本身的機制來說,繼承與多態都是提供父子關系的縱向關系描述,而橫向的關系描述,則反映得并不是很好,接口通過一定的實現機制,則部分性地彌補了這個空缺。
像代碼中所描述那樣,接口僅是作為一個便利性的工具存在,在面向接口的編程中,提供一切都圍繞接口而進行,所以,在此類的編程模式下,可以采用接口為替換一個方法實現提供十分理想的方式,雖然這比起濫用繼承并沒有什么優勢,但它是一個思想與觀念上的轉變,從本質上來說,接口映射與繼承中的new一樣,作為技巧用用可以,但它本身并不是一個值得推薦的方式。
總結
以上是生活随笔為你收集整理的接口映射的实现及原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL 2005 数据库镜像
- 下一篇: 圣诞快乐!灯火点不燃圣经