對接口方法的調用和采用索引指示器訪問的規則與類中的情況也是相同的。如果底層成員的命名與繼承而來的高層成員一致,那麼底層成員將覆蓋同名的高層成員。但由於接口支持多繼承,在多繼承中,如果兩個父接口含有同名的成員,這就產生了二義性(這也正是C#中取消了類的多繼承機制的原因之一),這時需要進行顯式的聲明。
程序清單15-2:
using System; interface ISequence { int Count{get;set;} } interface IRing { void count(int i); } interface IRingSequence:ISequence,IRing{} class C { void Test(IRingSequense rs){ //rs.Count(1); 錯誤,Count有二義性 //rs.Count=1; 錯誤,Count有二義性 ((ISequence)rs).Count=1; //正確 ((IRing)rs).Count(1); //正確調用IRing Count } }
上面的例子中,前兩條語句x.Count(1)和x.Count=1會產生二義性,從而導致編譯時錯誤,因此必須顯式地給X指派父接口類型,這種指派在運行時不會帶來額外的開銷。
再看下面的例子:
程序清單15-3:
using System; interface IInteger { void Add(int i); } interface IDouble { void Add(double d); } interface INumber:IInteger,IDouble{} class C { void Test(INumber n){ //n.Add(1);錯誤 n.Add(1.0); //正確 ((IInteger)n).Add(1); //正確 ((IDouble)n).Add(1); //正確 } }
調用n.Add(1)會產生二義性,因為候選的重載方法的參數類型均適用。但是,調用n.Add(1.0)是允許的,因為1.0是浮點數,參數類型與方法IInteger.Add()的參數類型不一致,這時只有IDouble.Add才是適用的。不過只要加入了顯式的指派,就決不會產生二義性。
接口的多重繼承的問題也會帶來成員訪問上的問題。
interface IBase { void F(int i); } interface ILeft:IBase { new void F(int i); } interface IRight:IBase { void G(); } interface IDerived:ILeft,IRight{} class A { void Test(IDerived d){ d.F(1); //調用ILeft.F ((IBase)d).F(1); //調用IBase.F ((ILeft)d).F(1); //調用ILeft.F ((IRight)d).F(1); //調用IBase.F } }
上例中,方法IBase.F在派生的接口ILeft中被ILeft的成員方法F覆蓋了。所以對d.F(1)的調用實際上調用了。雖然從IBase----IRight---IDerived這條繼承路徑上來看,ILeft.F方法是沒有被覆蓋的。
我們只要記住這一點:一旦成員被覆蓋以後,所有對其的訪問都被覆蓋以後的成員“攔截”了。