最近在園子里閑逛看到一篇文章“(抽象)類和接口細(xì)節(jié)分析”,盡管作者很細(xì)心很細(xì)致??墒聦嵣螩#里面的interface沒那么簡單,interface有著大量不為人知的小秘密的說。
1、值類型也能實現(xiàn)接口。 盡管可能很多人連值類型都沒用過,但值類型可以實現(xiàn)接口,是一個非常有用的特性。當(dāng)值類型轉(zhuǎn)換為接口類型時,會自動裝箱成引用類型從而實現(xiàn)多態(tài),但一般用值類型實現(xiàn)接口的老鳥都不會被這些小陷阱所迷惑的。
2、除了接口,沒有什么類型可以不實現(xiàn)接口 抽象類可以不實現(xiàn)接口?其實不然,抽象類只能抽象接口的實現(xiàn),即將實現(xiàn)變?yōu)閍bstract的,但不能不實現(xiàn)接口。也許你會疑惑,abstract實現(xiàn)接口成員和不實現(xiàn)接口成員到底有區(qū)別?盡管區(qū)別不大,但還是存在的,從理論上來說的話,就是slot上的方法的區(qū)別。抽象類用abstract成員實現(xiàn)接口后,子類再override來實現(xiàn)抽象類的abstract成員,這會使得子類的實現(xiàn)是在abstract實現(xiàn)之下而不是直接在接口成員之下。從實際效果上來說,由于抽象類的abstract的實現(xiàn)存在,使得子類中可以選擇對抽象類和接口進(jìn)行分別實現(xiàn)(重新實現(xiàn)接口)。
3、但事實上接口也不能實現(xiàn)接口,只是把多個接口捆綁起來。 一段有趣的代碼如下 public interface IA { void Test(); } public interface IB : IA { } public interface IC : IA { } public interface ID : IB, IC { } 當(dāng)實現(xiàn)ID時,等于同時實現(xiàn)ID、IC、IB和IA,但事實上,你只需要實現(xiàn)一個Test方法,也只能實現(xiàn)一個Test方法,也就是IA.Test,IB、IC、ID都是沒有Test方法的。 當(dāng)然,你可以嘗試在IB或是其他接口中再放入一個Test,便會產(chǎn)生一些奇妙的事情。
4、同一接口成員在同一類型中只能被實現(xiàn)一次。 顯示實現(xiàn)接口已經(jīng)不是什么秘密了,但很多人卻并不知道,如果你顯示實現(xiàn)了接口,那么隱式實現(xiàn)就不存在了。這就是接口只能被實現(xiàn)一次:
public interface IA { void Test(); } public interface IB { void Test(); } public class TestClass : IA, IB { public void Test() { throw new NotImplementedException(); } void IB.Test() { throw new NotImplementedException(); } }
在這段代碼中,第一個Test方法實際上只實現(xiàn)了IA.Test,而如果將第二個Test方法去掉,則第一個方法就會同時實現(xiàn)兩個Test,即IA.Test和IB.Test。不妨自己動手去試一下。
5、同一個類型也只能實現(xiàn)同一個接口一次。 其實不論類型的父類重復(fù)實現(xiàn)了同一個接口多少次,一個類型只能實現(xiàn)一個接口一次??紤]下面的代碼: public interface ITest { void Test(); } public abstract class Test1 : ITest { public void Test() { throw new NotImplementedException(); } } public abstract class Test2 : Test1, ITest { public new void Test() { throw new NotImplementedException(); } } public abstract class Test3 : Test2, ITest { public new void Test() { throw new NotImplementedException(); } } 無論在基類中實現(xiàn)了多少次ITest接口,事實上在ITest3的接口列表中永遠(yuǎn)只有一個ITest(GetInterfaces),也只能對ITest的每個成員實現(xiàn)一次(隱式或顯式)。
6、實現(xiàn)接口的成員實際可見性總是不低于接口可見性。顯示實現(xiàn)接口的成員可見性總是等同于接口可見性(因為它們默認(rèn)都是private的)。 重寫基類成員的成員必須有相同的可見性,接口則不必,隱式實現(xiàn)總是要求成員必須為public。同時,一個類型可以實現(xiàn)可見性比自己高或低的接口,但不能繼承可見性比自己低的基類。 因為能訪問到接口的類型的地方一定能訪問到接口的實現(xiàn)成員,所以實現(xiàn)接口的成員的實際可見性總不低于接口。 一個很常見的手法,一個可見性較低的類型通過可見性高的接口來暴露自己的成員,事實幾乎所有的枚舉器(IEnumerator的實例)都是private的類型,透過接口來暴露功能。
當(dāng)然,你也可以設(shè)計一個internal的接口,然后讓某個類型去“顯示實現(xiàn)”,這個時候?qū)崿F(xiàn)接口的成員的“實際”可見性將跟隨接口變?yōu)閕nternal。 由于隱式實現(xiàn)接口要求成員必須是public的,如果要用可見性較低的接口來制約成員可見性就只能用顯式實現(xiàn)接口成員。也許有人會很奇怪我干嘛降級成員的可見性?因為有時候可見性高了并不是什么好事,它會破壞組件(不是類型)的封裝。當(dāng)然更多的時候,我們只是需要一個手段來統(tǒng)一設(shè)置某些成員的可見性。
不過,我們也能想出更多非常好玩的玩法: public abstract class Test { protected interface ITest { void Test(); } public class Nested : ITest { void ITest.Test() { throw new NotImplementedException(); } } }
這也是顯示實現(xiàn)接口特性除了解決名稱和沖突問題之外最大的用處。 |
|