參考型別構造器是將類型的執行個體初始化為良好狀態的特殊方法,建立參考型別的執行個體時,首先為執行個體的資料欄位分配記憶體,然後初始化對象的附加欄位(類型對象指標和同步塊索引),最後調用類型的執行個體構造器來設定對象的初始化狀態。構造參考型別對象時,在電泳類型的執行個體構造器之前,為對象分配的記憶體總是先被歸0,沒有被構造器顯示重寫的所有欄位都保證獲得0或null值。和其他方法不同,實力構造器永遠不能被繼承,也就是說,類只有類自己定義的還順利構造器。由於永遠不能繼承執行個體構造器,所以執行個體構造器不能使用以下修飾符:Virtual,new,override,sealed和abstract。如果類沒有顯示定義任何構造器,C#編譯器將預設一個預設無參構造器,在她的實現中,只是簡單的調用了基類的無參建構函式。如果類的修飾符為abstract,那麼編譯器產生的預設構造器的可訪問性就為product;否則,構造器會被賦予public可訪問屬性。如果基類沒有提供無參構造器,那麼衍生類別必須顯示調用一個基類構造器,否則編譯器會報錯。如果類的修飾符為static(sealed和abstract),編譯器根本不會再類的定義中產生預設的構造器。一個類型可以定義多個執行個體構造器。每個構造器都必須有不同的簽名,而且每個都可以有不同的可訪問屬性。為了使代碼“可驗證”,類的實力構造器在訪問從基類繼承的任何欄位前,必須先調用基類的構造器。如果衍生類別的構造器沒有顯示調用一個基類構造器,C#編譯器會自動產生對預設的基類構造器的調用。最終,System.Object的公用無參構造器會得到調用。該構造器什麼都不做,會直接返回,由於System.Object沒有執行個體資料欄位,所以它的構造器無事可做。極少數情況下可以在不調用執行個體構造器的前提下建立類型執行個體。一個典型的例子就是Object的MemberwiseClone方法。該方法的作用是分配記憶體,初始化對象的附加欄位,然後將來源物件的自己資料複製到新對象中。另外,用運行時序列化器(runtime seriallizer)還原序列化對象時,同程也不需要調用構造器。還原序列化使用System.Runtime.Serialization.FormatterServices類型的GetUninitalizedObject或者GetSafeUninitailizedObject方法為對象分配記憶體,期間不會調用一個構造器。 提示:不要再構造器中調用虛方法。原因是假如被執行個體化的類型重寫了虛方法,就會執行衍生類別型對虛方法的實現,但是在這個時候,尚未完成對繼承階層中所有欄位的初始化(被執行個體化的類型的構造器還沒有運行)。所以,調用虛方法會導致無法預測的行為。歸根到底,這是由於調用虛方法時,直到運行時之前都不會選擇執行該方法的實際類型。 實值型別(struct)構造器實值型別(struct)構造器的工作方式與參考型別(class)的構造器截然不同。CLR總是允許建立實值型別的執行個體,並且沒有辦法阻止實值型別的執行個體化。所以,實值型別其實並不需要定義構造器,C#編譯器根本不會為實值型別內聯預設無參構造器。來看下面代碼:internal struct Point {public int m_x, m_y;} internal sealed class Reactangel{public Point m_TopLeft, m_bottomRight;}為了構造一個Rectangle,必須使用new操作符,而且必須指定構造器。在這個例子中,調用的是C#編譯器自動產生的預設構造器。為Reatangle分配記憶體,記憶體中包含Point實值型別的兩個執行個體。考慮到效能,CLR不會為包含在參考型別中的每個實值型別欄位都主動調用構造器,但是,如前所述,實值型別的欄位都會被初始化為0或null。CLR確實允許為實值型別定義構造器,但是必須顯示調用才會執行。internal struct Point {public int m_x, m_y; public Point(int x, int y){m_x = x;m_y = y;}} internal sealed class Reactangel{public Point m_TopLeft, m_bottomRight;public Reactangel(){this.m_TopLeft = new Point(1,2);this.m_bottomRight = new Point(100,200);}} 實值型別的執行個體構造器只有顯示調用才會執行。因此,如果Rectangle的構造器沒有使用new操作符來調用Point的構造器,從而初始化Reatangle的m_TopLeft和m_bottomRight欄位,那麼兩個point欄位中的m_x和m_y欄位都將為0.將上面代碼改寫:internal struct Point {public int m_x, m_y; public Point(){m_x = 5;m_y = 6;}} internal sealed class Reactangel{public Point m_TopLeft, m_bottomRight;public Reactangel(){}}現在,構造新的Rectangle類時,兩個Point欄位中的m_x和m_y欄位會被初始化多少,是0還是5?可能你會覺得C#編譯器會子啊Reactangel的構造器中產生代碼,為Reactangel的兩個欄位自動調用Point的預設無參構造器。但是,為了增強應用程式的運行時效能,C#編譯器不會自動產生這樣的代碼。實際上,即便實值型別提供了無參構造器,許多編譯器也永遠不會產生代碼來調用它,為了執行實值型別無參構造器,開發人員必須增加顯示調用實值型別構造器的代碼。但是會由於這個原因Point‘的兩個欄位被初始化為0嗎?結果是: C#編譯器故意不允許實值型別定義無參構造器,目的是防止開發人員對這種構造器在什麼時候調用產生迷惑。由於不能定義無參構造器,所以編譯器永遠不會產生自動調用它的代碼,沒有無參構造器,實值型別的欄位總是被初始化為0或null。 類型構造器:也稱為靜態構造器,類構造器或者類型初初始化器。類型構造器可應用與參考型別和實值型別。執行個體構造器的作用是設定類型的執行個體的初始狀態。對應的,類型構造器的作用是設定類型的初始狀態。類型預設沒有定義類型構造器,如果定義,也只能有一個。此外,類型構造器永遠沒有參數。internal sealed class SomeRefType {static SomeRefType(){//首次訪問時,執行這裡的代碼}} internal struct SomeValType{static SomeValType(){//首次訪問時,執行這裡的代碼}}可以看出,定義類型構造器類似於定義無參執行個體構造器,區別在於必須標記為static。此外,類型構造器總是私人的。之所以私人,是為了防止任何開發人員寫代碼調用它,對他的調用總是有CLR負責。提示:雖然能在實值型別中定義類型構造器,但永遠不要真的那麼做,因為CLR有時不會調用實值型別的靜態構造器:例如internal struct SomeValType{static SomeValType(){Console.WriteLine("這句話永遠不會顯示");}public int m_x;}class Program{static void Main(string[] args){SomeValType[] a = new SomeValType[10];a[0].m_x = 123;Console.WriteLine(a[0].m_x);Console.ReadKey();}}類型構造器的代碼只能訪問類型的靜態欄位,並且他的非常規用途就是初始化這些欄位。