不知道你們在使用繼承的過程當中有木有遇到過調用構造函數時沒有按照咱們預期的那樣執行呢?通常狀況下,出現這樣的問題每每是由於類繼承結構中的某個基類沒有被正確實例化,或者沒有正確給基類構造函數提供信息,若是理解在對象生命週期的這個階段發生的事情,將更利於解決此類問題。函數
爲了實例化派生的類,必須先實例化它的基類。而要實例化這個基類。又必需要實例化這個基類的基類,這樣一直到實例化System.Object(全部類的跟)爲止,結果不管使用什麼構造函數實例化一個類,老是首先調用System.Object.Object().this
下面一個示例演示執行順序:spa
基類:3d
public class MyBaseClass { public MyBaseClass() { Console.WriteLine("I am MyBaseClass()"); } public MyBaseClass(int i) { Console.WriteLine("I am MyBaseClass(int i)"); } }
派生類:code
public MyDerivedClass() { Console.WriteLine("I am MyDerivedCalss()"); } public MyDerivedClass(int i) { Console.WriteLine("I am MyDerivedClass(int i)"); } public MyDerivedClass(int i,int j) { Console.WriteLine("I am MyDerivedClass(int i,int j)"); }
接下來咱們在Main函數中以不帶參數的構造函數實例化MyDerivedClass:對象
MyDerivedClass myObj = new MyDerivedClass();
運行程序,控制檯輸出以下:blog
從結果能夠看出,執行順序先是基類構造的函數,接下來纔是派生類的構造函數,即繼承
1.執行System.Object.Object()構造函數(Object比較特殊,全部類的基類,通常能夠不考慮,可是得知道它也是被執行了的)生命週期
2.執行MyBaseClass.MyBaseClass()構造函數事件
3.執行MyDerivedClass.MyDerivedClass()構造函數
若是咱們以帶一個參數的構造函數實例化MyDerivedClass:
MyDerivedClass myObj = new MyDerivedClass(4);
運行程序,控制檯輸出以下:
能夠看出執行順序以下:
1.執行System.Object.Object()構造函數
2.執行MyBaseClass.MyBaseClass()構造函數
3.執行MyDerivedClass.MyDerivedClass(int i)構造函數
同理若是咱們以帶兩個參數的構造函數實例化MyDerivedClass
MyDerivedClass myObj = new MyDerivedClass(4,8);
運行程序,控制檯輸出以下:
能夠看出執行順序以下:
1.執行System.Object.Object()構造函數
2.執行MyBaseClass.MyBaseClass()構造函數
3.執行MyDerivedClass.MyDerivedClass(int i,int j)構造函數
大多數狀況下這個都能正常工做,可是有時咱們須要對發生的事件進行更多的控制。好比咱們想獲得以下所示的執行順序:
1.執行System.Object.Object()構造函數
2.執行MyBaseClass.MyBaseClass(int i)構造函數
3.執行MyDerivedClass.MyDerivedClass(int i,int j)構造函數
使用這個順序,能夠把使用int i參數的代碼放到MyBaseClass(int i)中,MyDerivedClass(int i,int j)只須要處理int j(假設int i參數在MyBaseClass和 MyDerivedClass裏含義是同樣的)
爲此,只須要使用構造函數初始化器,把代碼放到方法定義的冒號後面,如在派生類的構造函數中指定所使用的基類的構造函數,以下所示:
public MyDerivedClass(int i,int j) : base(i) { Console.WriteLine("I am MyDerivedClass(int i,int j)"); }
其中,base關鍵字指定在實例化過程當中使用具備指定參數的構造函數。這裏使用了int參數,其值經過i傳遞給MyDerivedClass構造函數,因此將使用MyBaseClass(int i),這樣就不會調用MyBaseClass()了,咱們從新執行下前面兩個參數的實例化代碼,就能夠看出執行結果確實如此:
除了base關鍵字,還可使用this關鍵字用做構造函數初始化器,這個關鍵字指定在調用指定的構造函數前,實例化過程對當前類使用非默認的構造函數。例如:
public MyDerivedClass():this(5,6) { Console.WriteLine("I am MyDerivedCalss()"); }
使用MyDerivedCalss()構造函數實例化,執行順序是:
1.執行System.Object.Object()構造函數
2.執行MyBaseClass.MyBaseClass(int i)構造函數
3.執行MyDerivedClass.MyDerivedClass(int i,int j)構造函數
4.執行MyDerivedClass.MyDerivedClass()構造函數
總之呢,不管派生類上使用什麼樣的構造函數(默認的or不是默認的),除非明確指定(如使用base關鍵字),不然就先調用用基類的默認構造函數。