這個做法在討論在衍生類別使用 new 和 override 對基底類別的影響,內容基本上與 LSP 原則重疊。
首先建立一組測試範例:
void Main()
{
BaseClass bc = new BaseClass();
DerivedClass dc = new DerivedClass();
BaseClass bcdc = new DerivedClass();
bc.Method1();
bc.Method2();
dc.Method1();
dc.Method2();
bcdc.Method1();
bcdc.Method2();
}
class BaseClass
{
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
public void Method2()
{
Console.WriteLine("Base - Method2");
}
}
class DerivedClass : BaseClass
{
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
從輸出的結果來看 bc
與 dc
的執行結果比較沒有爭議,符合預計的結果。
Base - Method1
Base - Method2
Derived - Method1
Derived - Method2
Derived - Method1
Base - Method2
需要討論的是 bcdc
執行的結果,可以看出 dc
與 bcdc
同樣都是 new DerivedClass()
,而且同樣都是呼叫 Method1 與 Method2
唯一的區別是 bcdc
使用的是基底的類型,這個細微的差別就很容易混淆開發者,並且也違反 LSP 原則,也就是 「子型態(subtype)必須能夠替換掉它們的基底型態(base type)」。
但這也不代表要將所有基底類別的方法或屬性都設定為 virtual
,這個設計叫做「預設虛擬」,此設計會帶給開發者明白自己可以修改衍生類別的方法的行為,
這種全部都預設虛擬的設計也可能讓別人認為你沒有思考衍生類型方法被修改後的結果,所以正確的做法是詳細考慮後只將需要多型的方法與屬性設定為虛擬。
另外作者建議只有一種情況才建議使用 new
,也就是衍生類型實做了一個方法然後在未來基底類型也實做了相同名稱的方法時。
Summary
new
修飾詞需要小心使用,如果隨便使用它,會導致基底類型與衍生類型的方法產生不一致的行為。