CLR中說道,不要在構造函數中調用虛方法,原因是假如被實例化的類型重寫了虛方法,就會執行派生類型對虛方法的實現。但在這個時候,尚未完成對繼承層次結構中所有欄位的初始化。所以,調用虛方法會導致不可預測的行為。歸根結底,這是由於調虛方法時,直到運行時之前,都不會選擇執行該方法的實際類型。 在MSDN中, ...
CLR中說道,不要在構造函數中調用虛方法,原因是假如被實例化的類型重寫了虛方法,就會執行派生類型對虛方法的實現。但在這個時候,尚未完成對繼承層次結構中所有欄位的初始化。所以,調用虛方法會導致不可預測的行為。歸根結底,這是由於調虛方法時,直到運行時之前,都不會選擇執行該方法的實際類型。
在MSDN中,也給我我們詳細的提示和範例。
https://msdn.microsoft.com/en-us/library/ms182331.aspx
那我們就親手來測試一下,新建兩個類,Perople類,Chinese類,先不要看結果,看到下麵這兩個類,想想在實例化Chinese的時候,會是什麼輸出結果呢?
1 public class People
2 {
3 public People()
4 {
5 PeopleSayHello();
6 }
7
8 public virtual void PeopleSayHello()
9 {
10 Console.WriteLine("hello");
11 }
12 }
public class Chinese : People
{
private bool HaveAbility { get; set; }
public Chinese()
{
HaveAbility = true;
}
public override void PeopleSayHello()
{
Console.WriteLine((HaveAbility?"有":"沒有")+"能力說你好");
}
}
接下來來看調用和輸出結果吧:
是不是和你在腦海裡運行的結果相同?
其實原因在第一句話中已經說的比較清晰了,更通俗的說就是在派生類實例化的時候,如果沒有顯式調用基的任意一個構造函數,那麼預設選擇基類的無參構造。所以在本例中,實例化Chinese的時候,首先執行了基類的無參構造。
和實例構造器初始化的順序也相關,在創建實例的時候,首先為數據欄位分配記憶體,然後初始化對象附加欄位,包括類型對象的指針引用,最後才調用類型的構造函數設置對象的初始狀態。