建構函式這玩意也是面試官經常會問到的東西,我們知道一個類的狀態初始化就全靠它了,下面提幾個小問題。
Q:我看到Web專案裡面通常都有一個BasePage頁面,其中建構函式裡面做了許可權驗證,
請問為什麼要這麼做。
A: 既然這麼做了,那麼設計者肯定就知道了一個原則就是例項構造器中,父類構造器先於子類執行,那麼這個先執行就可
以做很多有意思的事情,比如你說的許可權驗證,可能有人會問為什麼要先於子類執行,剛才我也說了,建構函式是用於
初始化本類狀態的,這也叫“先掃屋子再請客”的道理吧~,然後風雨兼程的回溯到Object的ctor中。好了,現在來回答
你的問題,先把這個問題簡化一下,就不用web專案來演示了。
1 public class Program 2 { 3 static void Main(string[] args) 4 { 5 var b = new Bird(); 6 7 Console.Read(); 8 } 9 } 10 11 public class Animal 12 { 13 public Animal() 14 { 15 Console.WriteLine("running first... i'm animal, all must be running after me."); 16 } 17 } 18 19 public class Bird : Animal 20 { 21 public Bird() 22 { 23 Console.WriteLine("the next... i'm a cute bird."); 24 } 25 }
可以看到,確實Animal於Bird先執行,可能有人會問,那Animal呼叫的是誰的ctor呢?當然就是Object了,我們可以看看IL:
Q: 既然你說建構函式用於初始化類的初始狀態,那麼請問下,我現在有一串這樣的
json:{"Name":"smart","Age":2}。實體類如下圖,請問我的json序列化後,Age=?
1 [Serializable] 2 public class Bird 3 { 4 private string name = "smart"; 5 6 public string Name 7 { 8 get { return name; } 9 set { name = value; } 10 } 11 12 private int age = 2; 13 14 public int Age 15 { 16 get { return age; } 17 set { age = value; } 18 } 19 20 public Bird() 21 { 22 Age = 5; 23 } 24 }
A:其實這個問題的關鍵在於,反序列化的時候是否會呼叫建構函式的問題,先來通過Reflector看下原始碼,發現並沒有程式碼,覺得
有點小奇怪,就用ILSpy反編譯一下,同樣也沒有程式碼,不可否認,底層肯定是有程式碼執行的,要麼反編譯不出來,要麼clr用了
其他的方式,反正我們看不到實現原始碼,如果大家有什麼好意見可以幫幫我,謝謝了
Reflector截圖:
ILSpy截圖:
據資料說,裡面最後呼叫了FormatterServices裡面的GetSafeUninitializedObject來分配物件記憶體,分配完後就不走構造器
了,所以針對這個問題,只能記住了。最後為了驗證一下,執行完程式碼之後確實沒有走建構函式。
Q:我知道引用型別可以用構造器,那值型別為什麼不能定義無參構造器?
A:這個問題問的好,編譯器會根據效能考慮,不會呼叫值型別的建構函式,即使你強制的new一下也不會執行
1 namespace Sample 2 { 3 public class Program 4 { 5 static void Main(string[] args) 6 { 7 Point point = new Point(); 8 } 9 } 10 11 public struct Point 12 { 13 public int Age; 14 } 15 }
不過除非你自己顯示定義有參建構函式,而且值型別有個特點就是讀取之前必須初始化,否則會編譯不通過。
Q:請問在類建構函式中能做單例嗎?
A: 能不能做,就要看類構造器的特徵了,我們知道類構造器跟例項構造器一樣,他是用來初始化靜態欄位的,執行緒
訪問類構造器的時候內部會進行加鎖處理,所以多個執行緒同時訪問的時候,只會有一個執行緒執行了類構造器,所以
確實可以。