眾所周知,在一個類中對介面所定義方法的實現,預設是不會加上“virtual”關鍵字的。
一般的形式如下。
interface IMsg
{
void Message();
}
public class MyClass:IMsg
{
#region IMsg Members
public void Message()
{
// TODO: Add MyClass.Message implementation
Debug.WriteLine( "MyClass" );
}
#endregion
}
因此,那麼如果一個類型繼承了實現介面的類型,預設的情況下是無法重載介面所定義的方法。不過在子類中雖說可以用“new”關鍵字覆蓋父類的方法,但是這並不能代替介面所定義的方法,例如:
public class MyDerivedClass:MyClass
{
public new void Message()
{
Debug.WriteLine( "MyDerivedClass" );
}
}
//Only for test
MyDerivedClass d = new MyDerivedClass();
d.Message();// Prints “MyDerivedClass”
IMsg m = d as IMsg;
m.Message();// Prints “MyClass”
很明顯,這樣的寫法並不能達到我們真正想要的目的。那麼如何在多層繼承中,能使介面實現局部化,簡單說,就是在不同的類型中有不同的實現方法。一般來說,需要在原有的基礎上進行轉化,通常有四種解決方案。
第一種方法,在子類中增加介面標識,這樣就可以名正言順實現介面定義的方法。例如如上的改寫。
public class MyDerivedClass:MyClass, IMsg
{
public new void Message()
{
Debug.WriteLine( "MyDerivedClass" );
}
}
那麼如上改寫,對於前一部分測試代碼來說,運行正確;但是這樣的實現會存在潛在的Bug,例如:
//Only for test
MyDerivedClass d = new MyDerivedClass();
d.Message();//Print "MyDerivedClass"
IMsg m = d as IMsg;
m.Message();//Print "MyDerivedClass"
MyClass b = d;
b.Message();//Print "MyClass"
也就是說,這樣方法可以解決介面在多層繼承中的問題,但是處理得不完美。相對於這種方法,另外三種方法要好很多,但是這三種方法都牽扯到虛函數。
首先介紹的,也是最簡單的,就是在實現的時候,給介面定義的函數增加“virtual”標識。例如:
public class MyClass:IMsg
{
#region IMsg Members
public virtual void Message()
{
// TODO: Add MyClass.Message implementation
Debug.WriteLine( "MyClass" );
}
#endregion
}
public class MyDerivedClass:MyClass
{
public override void Message()
{
Debug.WriteLine( "MyDerivedClass" );
}
}
不過,我覺得這個方法有些投機,或者從某種意義上說,已經變更了介面定義。
那麼接下來介紹的,就是用抽象類別進行重新封裝。例如:
public abstract class MyClass:IMsg
{
#region IMsg Members
public abstract void Message();
#endregion
}
這種方法相對前面的一種方法來說,是比較正規的,但是給人一種多此一舉的感覺,除非為了後期能提供IMsg介面轉換,否則直接用如下的方式會更好。
public abstract class MyClass
{
public abstract void Message();
}
最後一種實現,也是我比較喜歡的一種,類似於以前文章中提到的IDisposable實現方法,那麼對於這個例子,可以如下改寫。
public class MyClass:IMsg
{
#region IMsg Members
public void Message()
{
// TODO: Add MyClass.Message implementation
ShowMessage();
}
#endregion
protected virtual void ShowMessage()
{
Debug.WriteLine( "MyClass" );
}
}
public class MyDerivedClass:MyClass
{
protected override void ShowMessage()
{
Debug.WriteLine( "MyDerivedClass" );
}
}
這樣的改寫,既保留介面的完整性,同時代碼比較直觀,介面實現是介面實現,虛函數重載是虛函數重載,兩者是分離的。不過相對於前兩個虛函數實現方法,這一個方法需要編寫的代碼要相對多一些,效率略低(因為調用介面方法需要調用兩個函數)。
介面只是聲明方法和屬性,方法的一些標識並沒有特殊限制,因此在實現的時候可以增加一些標識,除了“virtual”外,還有“abstract”和“sealed”。