Effective C# (Covers C# 6.0), (includes Content Update Program): 50 Specific Ways to Improve Your C#, 3rd Edition By Bill Wagner 讀後心得
虛方法若放置在基類的建構子中,會發生讓人無法預料的結果(視子類別覆寫的內容而定)。以日後維護的觀點來看,應避免這樣的設計。接著,比較 C++ 與 C# 對虛方法或抽象方法的處理方式有何不同。
考慮以下程式碼:
class B
{
protected B( )
{
vFunc( );
}
protected virtual void vFunc( )
{
Debug.WriteLine( "vFunc in B" );
}
}
class Derived : B
{
private readonly string _msg = "Set by initializer";
public Derived( string msg )
{
_msg = msg;
}
protected override void vFunc( )
{
Debug.WriteLine( _msg );
}
}
Client:
var d = new Derived( "Constructed by Client" );
輸出:
Set by initializer
依照 item 15 的結論 2. 物件建構順序以及 C# 對 virtual function 的定義(i.e. 由 runtime type 決定該呼叫哪個類別的實作,在此例子中 type 為 Derived)。但即便編譯與運行是合法的,也並非良好的設計;_msg 是由 Derived 的建構子決定,但此例子輸出卻是類別成員初始化時的字串。顯然這樣會造成混淆,設計原意是要輸出哪一個字串呢?
Note:C++ 在此例子中會輸出 vFunc in B,原因在於 C++ 會依照當下執行類別的建構子改變其 runtime type。
接下來如果我們把 B 與 vfunc 定義為 abstract 會如何?
abstract class B
{
protected B( )
{
vFunc( );
}
protected abstract void vFunc( );
}
class Derived : B
{
private readonly string _msg = "Set by initializer";
public Derived( string msg )
{
_msg = msg;
}
protected override void vFunc( )
{
Debug.WriteLine( _msg );
}
}
Client:
var d = new Derived( "Constructed by Client" );
• C# 仍然會輸出 Set by initializer。
• C++ 則會 crash。
結論:
1. 應避免在基類呼叫虛方法或抽象方法。
2. 了解 C++ 與 C# 在處理虛方法與抽象方法相異之處。
1. 應避免在基類呼叫虛方法或抽象方法。
2. 了解 C++ 與 C# 在處理虛方法與抽象方法相異之處。