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

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

提問人:劉團(tuán)圓發(fā)布時(shí)間:2020-12-07

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

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

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

    無論在派生類上使用什么構(gòu)造函數(shù)(默認(rèn)的構(gòu)造函數(shù)或非默認(rèn)的構(gòu)造函數(shù)),除非明確指定,否則就使用基類的默認(rèn)構(gòu)造函數(shù)(稍后將介紹如何改變這個(gè)行為)。下面介紹一個(gè)簡短示例,來演示執(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)

    {

    }

}

如果以下面的方式實(shí)例化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ù)情況下,這個(gè)系統(tǒng)都能正常工作。但是,有時(shí)需要對發(fā)生的事件進(jìn)行更多控制。例如,在上面的實(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è)順序,可以把使用int i參數(shù)的代碼放在MyBaseClass(int i)中,即MyDerivedClass(int i,int j)購造函數(shù)要做的工作較少,只需要處理intj參數(shù)(假定int i參數(shù)在兩種情況下的含義相同,雖然事情并非總是如此,但實(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í)例化過程使用基類中具有指定參數(shù)的構(gòu)造函數(shù)。這里使用了一個(gè)int參數(shù)(其值通過參數(shù)i傳遞給MyDerivedClass構(gòu)造函數(shù)),所以將使用MyBaseClass(int i)。這么做將不會調(diào)用MyBaseClass(),而是執(zhí)行本例前面列出的事件序列一也就是我們希望執(zhí)行的事件序列。

    也可以使用這個(gè)關(guān)鍵字指定基類構(gòu)造函數(shù)的字面值,例如,使用MyDerivedClass的默認(rèn)構(gòu)造函數(shù)來調(diào)用MyBaseClass的非默認(rèn)構(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)鍵字外,這里還可將另一個(gè)關(guān)鍵字this用作構(gòu)造函數(shù)初始化器。這個(gè)關(guān)鍵字指定在調(diào)用指定的構(gòu)造函數(shù)前,.NET實(shí)例化過程對當(dāng)前類使用非默認(rèn)的構(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è)構(gòu)造函數(shù)。但如上例所示,這并不是一個(gè)很嚴(yán)格的限制,因?yàn)槲覀內(nèi)钥梢詷?gòu)造相當(dāng)復(fù)雜的執(zhí)行順序。

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

public class MyBaseClass 

{

    public MyBaseClass() : this(5)

    {

    }

    public MyBaseClass(int i) : this()

    {

    }

}

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

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

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