你可以用new修飾符來重新定義一個從基類中繼承來的非虛成員。你可以這樣 做,但並不意味著需要這樣做。重新定義非虛方法會導致方法含意的混亂。如果 兩個相關的類是繼承關系,那麼很多開發人員可能會立即假設兩段代碼塊是做完 全相同的事情,而且他們也會這麼認為:
object c = MakeObject( );
// Call through MyClass reference:
MyClass cl = c as MyClass;
cl.MagicMethod( );
// Call through MyOtherClass reference:
MyOtherClass cl2 = c as MyOtherClass;
cl2.MagicMethod( );
一但使用了new修飾符以後,問題就完全 不一樣了:
public class MyClass
{
public void MagicMethod( )
{
// details elided.
}
}
public class MyOtherClass : MyClass
{
// Redefine MagicMethod for this class.
public new void MagicMethod( )
{
// details elided
}
}
這樣的實 際操作會讓很多開發人員迷惑。因為當你在同一個對象上調用相同的函數時,一 定希望它們執行同樣的代碼。但實際上是,一但你用不同的引用來調用同名的函 數,它們的行為是不一樣的,這感覺非常糟糕。它們是不一致的。一個 MyOtherClass類型的對象所表現的行為會因為你引用的方式不一樣而有所不同。 這就是new修飾符用在非虛成員上的後果。其實這只是讓你在類的名字空間中添 加了一個不同的方法(雖然它們的函數名是相同的)。
非虛方法是靜態綁 定的,不管哪裡的代碼,也不管在哪裡引用,MyClass.MagicMethod() 總是嚴格 的調用類中所定義的函數。並不會在運行時在派生類中查找不同的版本。另一方 面,虛函數動態的。運行時會根據不同的類型對象調用不同的版本。
建 議大家避免使用new修飾符來重新定義非虛函數,這並不要太多的解釋,就像推 薦大家在定義一個基類時應該用虛方法一樣。一個類庫的設計者應該按照合某種 約設計虛函數。也就表示你期望任何派生類都應該修改虛函數的實現。虛函數的 集合就相當於是定義了一個行為的集合,這些行為是希望在派生中重新實現的。 設計默認的虛函數就是說派生可以修改類中的所有虛的行為。這確實是說你不想 考慮所有派生類可能要修改行為的分歧問題。相反,你可以把時間花在考慮把什 麼樣的方法以及屬性設計成多態的。當然,只有它們是虛行為的時候才能這樣做 。不要考慮這樣會限制類的用戶。相反,應該認為這是給類型的用戶定義行為提 供了一個入口向導。
有且只有一種情況要使用new修飾符,那就是把類集 成到一個已經存在的基類上時,而這個基類中已經使用了存在的方法名,這時就 要使用new了(譯注:就是說基類與派生類都已經存在了,是後來添加的繼承關系 ,結果在添加繼承關系時,發現兩個類中使用了同樣的方法名,那麼就可以在派 生類中添加一個new來解決這個問題)。因為有些代碼已經依懶於類的方法名,或 者已經有其它程序集在使用這個方法。例如你在庫中創建了下面的類,使用了在 另一個庫中定義的BaseWidget:
public class MyWidget : BaseWidget
{
public void DoWidgetThings( )
{
// details elided.
}
}