靜態構造函數趣談!
類的靜態構造函數也叫類型構造器,靜態構造器,他調用的時刻由CLR來控制:
CLR會選擇如下時間之一來調用靜態構造函數:
1,在類型的第一個實例創建之前,或類型的非繼承字段或成員第一次訪問之前。這里的“之前”,代表前后銜接的意思。這里的時刻是精確的!
2,在非繼承的靜態字段或成員第一次訪問之前的某個時刻,具體時刻不定!
由于調用的時刻不確定,所以我們最好不要編寫依賴于特定的靜態構造函數的執行順序的代碼,這樣很容易產生不可預料的后果!
下面大家看三個Demo,我們來更加深入的看看靜態構造函數的一些有趣的行為:
Demo1:
static void Main(string[] args) { Console.WriteLine(B.strText); } public class A { public static string strText; static A() { strText = "aaaa"; } } public class B : A { static B() { strText = "bbbb"; } }
大家猜猜結果是什么,可能有人認為輸出的是bbbb,因為訪問B.strText需要調用B類的靜態構造函數static B()。實際上輸出的結果是aaaa,因為strText是類A的靜態字段,而類B只是繼承了這個字段,所以這里會調用類A的靜態構造函數static A(),所以輸出結果是aaaa。這也沒有什么真正可說的,相信大家都能看出這個結果的。
下面看看第二個Demo:
Demo2:
static void Main(string[] args) { B b = new B(); A a = new A(); Console.WriteLine(B.strText); } public class A { public static string strText; static A() { strText = "aaaa"; } } public class B : A { static B() { strText = "bbbb"; } }
在執行 new B(); 之前,B類的靜態構造函數會調用,也就是會調用:
static B()
{
strText="bbbb";
}
當執行到strText=“bbbb"的時候,這時需要訪問strText字段,而B的strText字段是從A類繼承的,所以這里需要會先調用:
static A()
{
strText="aaaa";
}
執行這個函數以后strText的值是aaaa
然后代碼又回到static B()中,這時才執行static B()中的strText="bbbb"這行,所以strText這時的值是bbbb
當執行A a=new A();的時候,不會在調用A的靜態構造函數了,因為前面已經調用過了,靜態函數在整個應用程序域的生命周期中只會調用一次!
請大家多指教啊!