C#中的接口 (转自吕振宇老师的blog)
原文:http://zhenyulu.cnblogs.com/archive/2006/04/18/377705.html
本文中所有圖示純為個人理解(參考了Assembly中元數據的存儲方式),與真實情況可能有所出入。
圖中綠色表示公有方法,紅色表示私有方法。
本文將通過以下四個案例來分析C#中的接口究竟是如何工作的。
1、公有方法實現接口方法
盡管C#在定義接口時不用指明接口方法的訪問控制方式,但默認接口方法均為public型(這可以從反編譯的IL代碼中看到)。下面是使用Reflector查看的接口IL代碼
.class?private?interface?abstract?auto?ansi?IControl {.method?public?hidebysig?newslot?abstract?virtual?instance?void?Paint()?cil?managed{} }實現接口的類需要實現所有接口方法。通常情況下,接口的實現方法也為public型。如下案例:
using?System?; interface?IControl? {void?Paint(); } public?class?EditBox:?IControl? {public?void?Paint()?{Console.WriteLine("Pain?method?is?called!");} } class?Test? {static?void?Main()?{EditBox?editbox?=?new?EditBox();?editbox.Paint();((IControl)editbox).Paint();} }程序的執行結果為:
Pain method is called! Pain method is called!接口就好像是關系型數據庫中的一對多表,一個接口對應多個接口方法,每個接口方法又對應虛擬方法表(VMT)中的某個公有或私有方法。上面代碼在內存中的鏡像可由下圖描述:
從圖中我們可以看到直接對Paint方法的調用以及通過接口對Paint方法的調用??梢娡ㄟ^接口對方法進行調用需要多出一道轉換工作,因此執行效率不如直接調用。
2、私有方法不能實現接口方法
如果想將接口方法直接實現為私有方法是辦不到的。下面的EditBox的代碼中Paint方法沒有特殊說明,默認為private,導致代碼無法執行:
using?System?; interface?IControl? {void?Paint(); } public?class?EditBox:?IControl? {void?Paint()?{Console.WriteLine("Pain?method?is?called!");}public?void?ShowPaint(){this.Paint();((IControl)this).Paint();} } class?Test? {static?void?Main()?{EditBox?editbox?=?new?EditBox();?editbox.ShowPaint();} }程序在編譯時將顯示如下編譯錯誤:““EditBox”不會實現接口成員“IControl.Paint()”。“EditBox.Paint()”或者是靜態、非公共的,或者有錯誤的返回類型?!?/p>
為什么會這樣呢?如圖:
這是由于接口規范中的方法默認的訪問權限是public,而類中的默認訪問權限是default,也就是說private,因此導致權限范圍收縮,兩者權限并不相同,所以必須將類的權限調整為public才可以使上面的代碼得以執行。
3、實現專門的接口方法(1)
代碼如下:
using?System?; interface?IControl? {void?Paint(); } public?class?EditBox:?IControl? {void?Paint()?{Console.WriteLine("Pain?method?is?called!");}void?IControl.Paint()?{Console.WriteLine("IControl.Pain?method?is?called!");}public?void?ShowPaint(){this.Paint();((IControl)this).Paint();} } class?Test? {static?void?Main()?{EditBox?editbox?=?new?EditBox();?editbox.ShowPaint();//editbox.Paint();((IControl)editbox).Paint();} }EditBox類擁有一私有Paint方法,但這并不是接口方法的實現(上例已經分析過)。EditBox類中還包含了一“void IControl.Paint()”方法, 是該方法復寫了接口的Paint方法,該方法是私有的(通過IL代碼可以看出)。
注意:“void IControl.Paint()”前不能加任何的修飾限定符號,諸如public、private等,這在C#的語法中是不允許的。該方法反編譯得到的IL代碼如下:
.class?public?auto?ansi?beforefieldinit?EditBoxextends?objectimplements?IControl {........method?private?hidebysig?newslot?virtual?final?instance?void?IControl.Paint()?cil?managed{.override?IControl::Paint} }程序運行時內存中的鏡像可簡化表示為:
程序執行結果如下:
Pain method is called! IControl.Pain method is called! IControl.Pain method is called!我們之所以可以通過((IControl)editbox).Paint()方法訪問到代碼是因為接口方法Paint是公有的。但是我們不能通過editbox.Paint()方法訪問到代碼是因為EditBox的Paint方法是私有的。 在EditBox內部,通過ShowPaint方法可以同時訪問私有的Paint方法與接口IControl.Paint方法。
4、實現專門的接口方法(2)
如果EditBox中的Pait方法為公有并且同時提供了IControl.Paint方法,程序將是如何運行的呢?代碼如下:
using?System?; interface?IControl? {void?Paint(); } public?class?EditBox:?IControl? {public?void?Paint()?{Console.WriteLine("Pain?method?is?called!");}void?IControl.Paint()?{Console.WriteLine("IControl.Pain?method?is?called!");} } class?Test? {static?void?Main()?{EditBox?editbox?=?new?EditBox();?editbox.Paint();((IControl)editbox).Paint();} }程序執行結果如下:
Pain method is called! IControl.Pain method is called!程序執行時內存布局如下:
可見,EditBox中公有的Paint方法并不是接口實現方法,真正的接口實現方法是IControl.Paint,這將導致editbox.Paint()方法與((IControl)editbox).Paint()的執行結果并不一樣。
5、結論
接口方法的實現通常是通過類中的公有方法實現的;
在一些特殊情況下(代碼隱藏、一個類實現的兩個接口具有相同的接口方法等),需要專門實現某個接口的方法。
轉載于:https://www.cnblogs.com/dagon007/archive/2006/04/18/378307.html
總結
以上是生活随笔為你收集整理的C#中的接口 (转自吕振宇老师的blog)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DirectShow学习
- 下一篇: ASP.NET2.0 ObjectDat