位置:首頁 > 軟件操作教程 > 編程開發(fā) > C# > 問題詳情

C# 構(gòu)造函數(shù)的執(zhí)行序列

提問人:劉團圓發(fā)布時間:2020-12-07

    如果在類的構(gòu)造函數(shù)中執(zhí)行多個任務,把這些代碼放在一個地方是非常方便的,這與把代碼放在函數(shù)中具有相同的優(yōu)勢。使用一個方法就可以把代碼放在一個地方,但C#提供了一種更好的方式。任何構(gòu)造函數(shù)都可以配置為在執(zhí)行自己的代碼前調(diào)用其他構(gòu)造函數(shù)。 .

    在討論構(gòu)造函數(shù)前,先看一下在默認情況下,創(chuàng)建類的實例時會發(fā)生什么。除了前面說過的便于把初始化代碼集中起來外,還要了解這些代碼。在開發(fā)過程中,由于調(diào)用構(gòu)造函數(shù)時可能出現(xiàn)錯誤,對象常常并沒有按照預期的那樣執(zhí)行。發(fā)生構(gòu)造函數(shù)調(diào)用錯誤常常是因為類繼承結(jié)構(gòu)中的某個基類沒有正確實例化,或者沒有正確地給基類構(gòu)造函數(shù)提供信息。如果理解在對象生命周期的這個階段發(fā)生的事情,將更利于解決此類問題。

    為了實例化派生的類,必須實例化它的基類。而要實例化這個基類,又必須實例化這個基類的基類,這樣一直到實例化Systera.ObjeCt(所有類的根)為止。結(jié)果是無論使用什么構(gòu)造函數(shù)實例化一個類,總是首先調(diào)用System.Object.Object()。

    無論在派生類上使用什么構(gòu)造函數(shù)(默認的構(gòu)造函數(shù)或非默認的構(gòu)造函數(shù)),除非明確指定,否則就使用基類的默認構(gòu)造函數(shù)(稍后將介紹如何改變這個行為)。下面介紹一個簡短示例,來演示執(zhí)行順序。考慮下面的對象層次結(jié)構(gòu):

public class MyBaseClass

{

    public MyBaseClass()

    }

    public MyBaseClass(int i)

    {

    }

}

public class MyDerivedClass : MyBaseClass 

{

    public MyDerivedClass()

    {

    }

    public MyDerivedClass(int i)

    {

    }

    public MyDerivedClass(int i, int j)

    {

    }

}

如果以下面的方式實例化MyDerivedClass:

MyDerivedClass myObj = new MyDerivedClass();

則執(zhí)行順序如下:

    ?執(zhí)行 System.Object.Object()構(gòu)造函數(shù)。

    ?執(zhí)行 MyBaseClass.MyBaseClass()構(gòu)造函數(shù)。

    ?執(zhí)行 MyDerivedClass.MyDerivedClass()構(gòu)造函數(shù)。 

另外,如果使用下面的語句:

    MyDerivedClass myObj = new MyDerivedClass(4)?

則執(zhí)行順序如下:

    ?執(zhí)行 System.ObjectObject()構(gòu)造函數(shù)。

    ?執(zhí)行 MyBaseClass.MyBaseClass()構(gòu)造函數(shù)。

    ?執(zhí)行 MyDerivedClass.MyDerivedClass(int i)構(gòu)造函數(shù)。 

    最后,如果使用下面的語句:

MyDerivedClass myObj = new MyDerivedClass(4, 8);

則執(zhí)行順序如下:

    ?執(zhí)行 System.Object.Object()構(gòu)造函數(shù)。

    ?執(zhí)行 MyBaseClass.MyBaseClass()構(gòu)造函數(shù)。

    ?執(zhí)行 MyDerivedClass.MyDerivedClass(int i, int j)構(gòu)造函數(shù)。

    大多數(shù)情況下,這個系統(tǒng)都能正常工作。但是,有時需要對發(fā)生的事件進行更多控制。例如,在上面的實例化示例中,可能想得到如下所示的執(zhí)行順序:

    ?執(zhí)行 System.Object.Object()構(gòu)造函數(shù)。

    ?執(zhí)行 MyBaseClass.MyBaseClass(int i)構(gòu)造函數(shù)。

    ?執(zhí)行 MyDerivedClass.MyDerivedClass(int i,int j)構(gòu)造函數(shù)。

    使用這個順序,可以把使用int i參數(shù)的代碼放在MyBaseClass(int i)中,即MyDerivedClass(int i,int j)購造函數(shù)要做的工作較少,只需要處理intj參數(shù)(假定int i參數(shù)在兩種情況下的含義相同,雖然事情并非總是如此,但實際上我們常做這樣的安排)。只要愿意,C#就可以指定這種操作。

    為此,只需要使用構(gòu)造函數(shù)初始化器(constructor initializer),它把代碼放在方法定義的冒號后面。例如,可以在派生類的構(gòu)造函數(shù)定義中指定所使用的基類構(gòu)造函數(shù),如下所示:

public class MyDerivedClass : MyBaseClass

{

    ...

    public MyDerivedClass(int i, int j) : base(i)

    {

    }

}

    其中,base關(guān)鍵字指定.NET實例化過程使用基類中具有指定參數(shù)的構(gòu)造函數(shù)。這里使用了一個int參數(shù)(其值通過參數(shù)i傳遞給MyDerivedClass構(gòu)造函數(shù)),所以將使用MyBaseClass(int i)。這么做將不會調(diào)用MyBaseClass(),而是執(zhí)行本例前面列出的事件序列一也就是我們希望執(zhí)行的事件序列。

    也可以使用這個關(guān)鍵字指定基類構(gòu)造函數(shù)的字面值,例如,使用MyDerivedClass的默認構(gòu)造函數(shù)來調(diào)用MyBaseClass的非默認構(gòu)造函數(shù):

public class MyDerivedClass : MyBaseClass 

{

    public MyDerivedClass() : base(5)

    {

    }

    ...

}

這段代碼將執(zhí)行下述序列:

    ?執(zhí)行 System.Object.Object()構(gòu)造函數(shù)。

    ?執(zhí)行 MyBaseClass.MyBaseClass(int i)構(gòu)造函數(shù)。

    ?執(zhí)行 MyDerivedClass.MyDerivedClass()構(gòu)造函數(shù)。

除了 base關(guān)鍵字外,這里還可將另一個關(guān)鍵字this用作構(gòu)造函數(shù)初始化器。這個關(guān)鍵字指定在調(diào)用指定的構(gòu)造函數(shù)前,.NET實例化過程對當前類使用非默認的構(gòu)造函數(shù)。例如:

public class MyDerivedClass : MyBaseClass 

{

    public MyDerivedClass() : this(5, 6)

    {

    }

    ...

    public MyDerivedClass(int i, int j) : base⑴

    {

    }

}

使用MyDerivedClass.MyDerivedClass()構(gòu)造函數(shù),將得到如下執(zhí)行順序: 

    ?執(zhí)行 System.Object.Object()構(gòu)造函數(shù)。

    ?執(zhí)行 MyBaseClass.MyBaseClass(int i)構(gòu)造函數(shù)。

    ?執(zhí)行 MyDerivedClass.MyDerivedClass(int i,int j)構(gòu)造函數(shù)。

唯一的限制是使用構(gòu)造函數(shù)初始化器只能指定一個構(gòu)造函數(shù)。但如上例所示,這并不是一個很嚴格的限制,因為我們?nèi)钥梢詷?gòu)造相當復雜的執(zhí)行順序。

注意在定義構(gòu)造函數(shù)時,不要創(chuàng)建無限循環(huán)。例如:

public class MyBaseClass 

{

    public MyBaseClass() : this(5)

    {

    }

    public MyBaseClass(int i) : this()

    {

    }

}

使用上述任何一個構(gòu)造函數(shù),都需要首先執(zhí)行另一個構(gòu)造函數(shù),而另一個構(gòu)造函數(shù)要求首先執(zhí)行原構(gòu)造函數(shù)。這段代碼可以編譯,但如果嘗試實例化MyBaseClass,就會得到一個SystemOverflowException異常。

繼續(xù)查找其他問題的答案?

相關(guān)視頻回答
回復(0)
返回頂部