C#類繼承中建構函式的執行序列
不知道大家在使用繼承的過程中有木有遇到過呼叫建構函式時沒有按照我們預期的那樣執行呢?一般情況下,出現這樣的問題往往是因為類繼承結構中的某個基類沒有被正確例項化,或者沒有正確給基類建構函式提供資訊,如果理解在物件生命週期的這個階段發生的事情,將更利於解決此類問題。
為了例項化派生的類,必須先例項化它的基類。而要例項化這個基類。又必須要例項化這個基類的基類,這樣一直到例項化System.Object(所有類的跟)為止,結果無論使用什麼建構函式例項化一個類,總是首先呼叫System.Object.Object().
下面一個示例演示執行順序:
基類:
public class MyBaseClass {public MyBaseClass() { Console.WriteLine("I am MyBaseClass()"); } public MyBaseClass(int i) { Console.WriteLine("I am MyBaseClass(int i)"); } }
派生類:
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();
執行程式,控制檯輸出如下:
從結果可以看出,執行順序先是基類構造的函式,接下來才是派生類的建構函式,即
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關鍵字),否則就先呼叫用基類的預設建構函式。