C#例項構造器,型別構造器 -筆記

gavinou發表於2006-09-26

例項構造器: (引用型別)

 例項構造器是一種特殊的方法,他們負責將型別(Class) 的例項初始化到一個良好的狀態.對於可驗證的程式碼,CLR要求每個類(引用型別)至少定義一個例項構造器。(可以是公開或私有)

在建立一個例項時系統將執行以下三個步驟:
1)首先為改例項分配記憶體;
2)然後初始化物件的附加成員(即方法表指標和一個SyncBlockIndex);
3)最後呼叫型別的構造器設定物件的初始狀態。

在預設情況下,如果我們沒有顯式為其定義例項構造器,許多編譯器(包括C#)都會為我們定義一個共有的無參構造器。

 

//C# 編譯器會為我們自動的定義一個預設的公有無參構造器
class SomeType
{
}


//上面的型別定義等同於下面的型別定義

class SomeType
{
  
public SomeType()
  
{
  }

}

 

 一個型別可以定義多個例項構造器,每個構造器都必須有一個不同的簽名。

多個構造器可以有不同的訪問限制。

一個類的例項構造器在訪問其積累的繼承欄位之前,必須呼叫基類的例項構造器。
  (許多編譯器,包括C#,都會自動產生對積累預設構造器(如果有的話)的呼叫程式碼,所以一般情況下,我們不用擔心這個問題。

在少數情況下,型別例項的建立不需要呼叫例項構造器。例如:
1)呼叫Object的MemberwiseClone方法。
2)在反序列化一個物件時,通常也不會呼叫構造器。

class SomeType
{
    Int32 x
=5;
    String s
="Hello";
    Double d
= 3.14;
    Byte b;
    
    
//下面是一些構造器
    public SomeType() {...}
    
public SomeType(Int32 x) {...}
    
public SomeType(String s(...,d=10;)
    
}

當編譯器為以上三個構造器方法產生程式碼時的步驟:
1)每個方法的開始出都將包括 x, s, d 的初始化的程式碼。
2)在這些初始化程式碼之後,編譯器才會為各個構造器新增出現在其中的程式碼。
  例如:對於接受String引數的那個構造器,編譯器產生的程式碼首先時初始化x,s,d, 然後才是將10賦值給d。

* 如果我們有一些需要初始化的例項欄位,以及有許多過載的構造方法,我們應該考慮在定義欄位的時候避免同時對他們進行初始化,相反,我們應該將這些公共的初始化語句放在一個初始化構造器中。然後讓其他的構造器顯式呼叫這個初始化構造器,這將有效減少生成程式碼的尺寸。

以上程式碼可以改為

class SomeType
{
    Int32 x;
    String s;
    Double d;
    Byte b;
    
    
//下面是一些構造器
    public SomeType() 
    
{
        x
=5;
        s
="Hello";
        d
=3.14;
    }

    
public SomeType(Int32 x) :this()
    
{        this.x=x;    }
    
    
public SomeType(String s):this()
    
{
        
this.s=s;
        d
=10;
    }

    
}

例項構造器:(值型別)

1)CLR沒有強制要求值型別中必須定義構造器方法。

2)CLR允許我們位置型別定義構造器。
       (注意:但C#不允許我們為一個值型別定義無參構造器)-編譯器會丟擲出錯提示。

3)一個值型別的例項構造器只有當被顯式呼叫時才會執行。(與引用型別的例項構造器不同)

struct SomeValType
{
    Int32 x,y;
    
public SomeValType(Int32 x) {
        
this.x=this.y=x;
    }

}

//正確的定義

class Ra {
    
public SomeValType val;
    
public Ra()
    
{
        val
= new SomeValType(1);
    }

}

//必須顯式使用構造器。

//以下是錯誤內容

struct SomeValType
{
    Int32 x
=5
}

//錯誤:因為C#不允許值型別有無參構造器,在編譯時會出錯:結構中不能有例項欄位初始值設定項

struct SomeValType
{
    Int32 x,y;
    
public SomeValType(Int32 x) {
        
this.x=x;
    }

}

//錯誤:y沒有被初始化,C#編譯器丟擲錯誤:。。。在控制離開構造器前,欄位SomeValType.y必須完全賦值。

 

型別構造器(又成為靜態構造器,類構造器)

1)預設情況下,一個型別中沒有定義型別構造器。

2)如果要定義型別構造器,也只能定義一個。

3)並且,型別構造器不能有任何引數

//當SomeType第一次被訪問是執行
class SomeType
{
    
static Int32 x;    
    
static SomeType()
    
{
        x
=10;
    }

}

struct SomeType
{
    
static Int32 x;    
    
static SomeType()
    
{
        x
=10;
    }

}

 

4)型別構造器必須是static,而且總是私有方式(預設只能由CLR完成,不能顯式指定)

5)型別構造器中的程式碼只能訪問型別的靜態欄位,並且通常他的目的就是初始化這些靜態欄位。

6)注意:型別構造器不應該呼叫其基型別的型別構造器。
    不需要這樣作是因為基型別中的靜態欄位並沒有被派生型別所繼承(而只是編譯時靜態繫結)

7)型別構造器的生成程式碼的順序與例項構造器中的處理方式完全相同

 

相關文章