本文主要介紹了c#類的構造方法。具有一定的參考價值,下面跟著小編一起來看下吧
一、構造方法
類的構造方法是類的成員方法的一種,它的作用是對類中的成員進行初始化操作。類的構造方法分為:
1.靜態構造方法
2.執行個體構造方法
1.靜態構造方法
類的靜態構造方法是類的成員方法的一種,它的作用是對類中的靜態成員進行初始化操作。下面請看代碼執行個體:
using System;namespace LycheeTest { class Test { //定義一個靜態成員變數 private static int a; //定義靜態建構函式 static Test() { //初始化靜態成員變數 a = 11; } public void Show() { Console.WriteLine("靜態欄位 a 的值是:{0}", a); } } class Program { static void Main(string[] args) { Test t = new Test(); t.Show(); Console.ReadKey(); } }}
首先,上面這段代碼定義了兩個類。第 3 行代碼定義了類 Test。定義類的時候,類的存取權限修飾符有兩個,一個是 public,另一個是 internal。當不寫任何存取修飾詞的時候,類的存取權限預設是 internal。 這個存取權限的意義是,這個類只能被本程式集訪問,不能被本程式集以外的類訪問。如果這個類是屬於類庫的,那麼它必須是 public 的,否則調用它的程式集就不能訪問它。第 5 行代碼定義了一個靜態欄位成員,第 7 行代碼就是靜態構造方法。可以看到,靜態構造方法的特點是,以 static 關鍵字說明這個方法是靜態,方法名稱要和類名完全相同,這裡要注意大小寫。靜態構造方法不能含有參數,靜態構造方法不能有傳回值。在靜態構造方法體內可以做初始化靜態成員的操作。第 11 行代碼定義了一個執行個體方法,它的作用是輸出靜態欄位的值。在第 16 行的類 Program 中的 Main(注意:在java中是main) 方法中調用了這個類,第 18行建立了這個類的一個執行個體,第 19 行 調用了類的執行個體方法。
從上面的代碼中可以看到,並沒有顯式調用類的靜態構造方法。
下面請看以上代碼的執行結果:
靜態欄位 a 的值是:11
可以看到,靜態構造方法確實是被執行了。那麼上例就是靜態構造方法的執行條件之一,在類的執行個體被建立時,類的靜態構造方法將被自動調用。
靜態構造方法的調用次序是在靜態欄位的初始值設定項之後。
也就是第一步是靜態欄位的預設值設定,第二步是執行靜態欄位的初始值設定項,第三步就是調用類的靜態構造方法。
下面將前面的代碼執行個體修改一下,代碼如下:
using System;namespace LycheeTest{ class Test { private static int a; static Test() { a++; } public void Show() { Console.WriteLine("靜態欄位 a 的值是:{0}", a); 14 } } class Program { static void Main(string[] args) { Test t = new Test(); t.Show(); Test t1 = new Test(); t.Show(); Console.ReadKey(); } }}
這段代碼將靜態構造方法做了修改,在方法體內將靜態欄位 a 進行自增操作。然後在代碼的第 17 行又 建立了一個類的執行個體,然後再次調用類的執行個體方法。
下面看執行結果:
靜態欄位 a 的值是:1 靜態欄位 a 的值是:1
可以看到,靜態欄位的值並沒有增加。這就是靜態構造方法執行的特點,它只執行了一次。當程式集 啟動並執行時候,將會建立一個應用程式定義域,在一個應用程式定義域中,類的靜態構造方法僅僅執行一次。
下面再對代碼執行個體進行修改如下:
using System;namespace LycheeTest { class Test { public static int a; static Test() { Console.WriteLine("類的靜態構造方法開始執行"); a++; } public void Show() { Console.WriteLine("靜態欄位 a 的值是:{0}", a); } } class Program { static void Main(string[] args) { Console.WriteLine("靜態欄位 a 的值是:{0}", Test.a); Console.WriteLine("靜態欄位 a 的值是:{0}", Test.a); Console.ReadKey(); } }}
這段代碼在類的靜態構造方法中列印輸出了一行標記,類的靜態欄位的存取權限也修改為 public,這讓它可以在類外被調用。在 Main 方法中兩次列印輸出了靜態欄位的值,注意在類外調用類的靜態欄位需要 使用類名進行引用。
下面是代碼的執行結果:
類的靜態構造方法開始執行靜態欄位 a 的值是:1靜態欄位 a 的值是:1
本段代碼並沒有建立類的執行個體。在引用類的靜態成員之前,類的靜態構造方法將被調用。這個被調用的類的靜態成員包括靜態欄位和靜態方法。這就是類的靜態構造方法調用的第二個條件。
下面再對代碼執行個體進行修改如下:
using System;namespace LycheeTest { class Program { private static int a; static Program() { Console.WriteLine("類的靜態構造方法被調用"); a = 11; } static void Main(string[] args) { Console.WriteLine("Main 方法被調用"); Console.WriteLine("靜態欄位 a 的值是:{0}", a); Console.ReadKey(); } }}
這段代碼在包含 Main 方法的類中定義了靜態欄位和靜態構造方法。因為 Main 方法也是一個靜態方法,類的靜態構造方法被調用而且它是類的進入點方法,那麼它和類的靜態構造方法之間是誰先調用呢?下面首先來看代碼的執行結果:
類的靜態構造方法被調用Main 方法被調用靜態欄位 a 的值是:11
通過代碼的執行結果可以看到,因為類的進入點方法仍然是一個靜態方法,那麼在任何靜態成員被調用之 前,靜態構造方法都首先被調用。所以,可以得出如下結論,類的靜態構造方法先於類的 Main 方法被調用。
那麼類的靜態構造方法能否被顯式調用呢?下面看代碼執行個體:
using System;namespace LycheeTest { class Program { private static int a; static Program() { Console.WriteLine("類的靜態構造方法被調用"); a = 11; } static void Main(string[] args) { Program(); Console.ReadKey(); } }}
在這段代碼中的第 10 行顯式調用了類的靜態構造方法,這時編譯器會報錯。
2.執行個體建構函式
類的執行個體構造方法是類的成員方法的一種,它的作用是對類的執行個體成員進行初始化操作。執行個體構造方法可以實現重載,在建立類的執行個體時,可以顯式的指定不同的參數來調用重載的不同的執行個體構造方法。下面請看代碼執行個體:
using System;namespace LycheeTest { class Program { private static int a; private int b = 12; private string c = "Hello World"; static Program() { Console.WriteLine("類的靜態構造方法被調用"); a = 11; } public Program(int a, string s) { Console.WriteLine("帶二個參數的構造方法被調用"); this.b = a; this.c = s; } public Program(int a) : this(a, "通過 this 關鍵字調用構造方法") { Console.WriteLine("帶一個參數的構造方法被調用"); } public void Show() { Console.WriteLine("靜態欄位 a 的值是:{0}", a); Console.WriteLine("執行個體欄位 b 的值是:{0}", b); Console.WriteLine("執行個體欄位 c 的值是:{0}", c); } static void Main(string[] args) { Program p1 = new Program(33, "這是建立的執行個體 P1"); Program p2 = new Program(34); p1.Show(); p2.Show(); Console.ReadKey(); } }
這段代碼的第 4 行、第 5 行和第 6 行分別定義了三個欄位成員,第 4 行是靜態欄位,第 5 行和第 6 行代碼都有初始值設定項。代碼的第 8 行就是一個執行個體構造方法的定義,執行個體構造方法也是以類名作為方法名,它沒有傳回值, 在方法名前面是存取權限修飾符,可以使用的存取權限修飾符包括 public、private 和 protected。其中的 protected 意味著構造方法只能在此類內部訪問。執行個體構造方法可以帶參數。 第 12 行代碼的執行個體構造方法使用兩個傳入的參數對執行個體欄位進行了賦值。第 17 行代碼定義了帶一個參數的執行個體構造方法,它和前一個執行個體構造方法形成了重載。執行個體構造方法可以通過 this 關鍵字調用其他的執行個體構造方法,方法就是在參數列表的後面使用冒號然後接 this 關鍵字, 然後再跟參數列表,這個參數列表要匹配另一個重載的執行個體構造方法。第 17 行的構造方法只有一個參數, 它將這個參數通過 this 關鍵字傳遞給了另一個構造方法,在用 this 調用另一個構造方法的時候,為其同時傳入了一個字串參數。第 24 行的執行個體方法列印類的欄位成員的值。在 Main 方法中,第 26 行代碼和第 27 行代碼分別定義了兩個執行個體,它們使用 new 關鍵字調用了不同的執行個體構造方法。第 28 行和第 29 行分別調用執行個體方法列印類的靜態欄位和執行個體的兩個欄位成員的值。
下面先來看代碼的執行結果:
類的靜態構造方法被調用 帶二個參數的構造方法被調用 帶二個參數的構造方法被調用 帶一個參數的構造方法被調用 靜態欄位 a 的值是:11 執行個體欄位 b 的值是:33執行個體欄位 c 的值是:這是建立的執行個體 P1 靜態欄位 a 的值是:11執行個體欄位 b 的值是:34執行個體欄位 c 的值是:通過 this 關鍵字調用構造方法
現在用執行結果來介紹執行個體構造方法的執行過程,當第 26 行代碼建立類的執行個體時,類的靜態欄位首先被設定成預設值,因為沒有欄位的初始值設定項,所以接著就執行類的靜態構造方法。這時靜態欄位 a 被 設定成 11。因為第 26 行代碼使用 new 調用了帶有兩個參數的執行個體構造方法,所以首先執行個體欄位 b 被設定為 0,執行個體欄位 c 被設定為 null。然後執列欄位的初始值設定項,b 被賦值為 12,c 被賦值為“Hello World”。接 下來執行執行個體構造方法體中的第一個語句,“帶二個參數的構造方法被調用”這個字串被列印。接下來 執行個體 p1 的欄位 b 被設定為傳入的參數 33,注意構造方法的形參 a 在這裡覆蓋了類的靜態欄位 a。也就是說, 這時起作用的是執行個體構造方法的局部變數 a。然後執行個體欄位 c 被設定為字串"這是建立的執行個體 P1"。第 27 行代碼使用 new 關鍵字調用了帶一個參數的執行個體構造方法,在調用時,首先屬於 p2 的執行個體欄位 b 被設定為 0,執行個體欄位 c 被設定為 null。然後執列欄位的初始值設定項,b 被賦值為 12,c 被賦值為“Hello World”。接下來執行的是 this 引用的帶兩個參數的執行個體構造方法,"帶二個參數的構造方法被調用"這個 字串被列印。然後 b 被設定為 34,c 被設定為"通過 this 關鍵字調用構造方法"。最後,代碼控制又返回 來執行帶一個參數的執行個體構造方法體中的列印語句,"帶一個參數的構造方法被調用"這個字串被列印。 至此,執行個體構造方法的執行完畢。接下來的代碼列印靜態欄位的值,可以看到兩個執行個體列印出來的靜態欄位值是一樣的,但是它們的實 例欄位的值各不相同。
選擇性參數和具名引數也可以用於執行個體構造方法,下面看代碼執行個體:
using System;namespace LycheeTest { class Program { private int b; private string c; public Program(int a = 12, string s = "") { this.b = a; this.c = s; } public void Show() { Console.WriteLine("執行個體欄位 b 的值是:{0}", b); Console.WriteLine("執行個體欄位 c 的值是:{0}", c); } static void Main(string[] args) { Program p1 = new Program(); //構造方法的兩個參數都採用預設值 Program p2 = new Program(34); //構造方法的 string 型別參數採用預設值 Program p3 = new Program(23, "Hello World"); //構造方法的兩個參數採用傳入參數 Program p4 = new Program(s: "今天的天氣真好"); //採用具名引數,另一個參數 a 採用預設值 p1.Show(); p2.Show(); p3.Show(); p4.Show(); Console.ReadKey(); } }}
代碼的第 6 行定義了一個帶有選擇性參數和具名引數的構造方法,然後第 15 建立了一個類的執行個體,在構造方法中沒有傳入任何參數,這時,構造方法的兩個參數都採用預設值。第 16 行代碼為構造方法傳入了一個 int 類型的參數,這時,另一個 string 類型的參數採用預設值。 第 17 行代碼傳入了兩個參數,構造方法的兩個參數都使用了這兩個傳入的參數。第 18 行代碼使用了具名引數指定傳入的參數是 string 類型的參數,並將它傳遞給形參 s。這時另一 個 int 類型的參數採用預設值。第 19 行到第 23 行代碼列印類的執行個體欄位的值。這段代碼的執行結果如下:
執行個體欄位 b 的值是:12 執行個體欄位 c 的值是: 執行個體欄位 b 的值是:34 執行個體欄位 c 的值是: 執行個體欄位 b 的值是:23執行個體欄位 c 的值是:Hello World 執行個體欄位 b 的值是:12執行個體欄位 c 的值是:今天的天氣真好