關於C#靜態建構函式的幾點說明
靜態建構函式是C#的一個新特性,其實好像很少用到。不過當我們想初始化一些靜態變數的時候就需要用到它了。這個建構函式是屬於類的,而不是屬於哪裡執行個體的,就是說這個建構函式只會被執行一次。也就是在建立第一個執行個體或引用任何靜態成員之前,由.NET自動調用。
class SimpleClass
{
// Static constructor
static SimpleClass()
{
//
}
}
在使用靜態建構函式的時候應該注意幾點:
1、靜態建構函式既沒有存取修飾詞,也沒有參數。因為是.NET調用的,所以像public和private等修飾符就沒有意義了。
2、是在建立第一個類執行個體或任何靜態成員被引用時,.NET將自動調用靜態建構函式來初始化類,也就是說我們無法直接調用靜態建構函式,也就無法控制什麼時候執行靜態建構函式了。
3、一個類只能有一個靜態建構函式。
4、無參數的建構函式可以與靜態建構函式共存。儘管參數列表相同,但一個屬於類,一個屬於執行個體,所以不會衝突。
5、最多隻運行一次。
6、靜態建構函式不可以被繼承。
7、如果沒有寫靜態建構函式,而類中包含帶有初始值設定的靜態成員,那麼編譯器會自動產生預設的靜態建構函式。
靜態建構函式趣談!
類的靜態建構函式也叫類型構造器,靜態構造器,他調用的時刻由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";
}
}
大家猜猜輸出結果是什麼,可能有人認為會輸出aaaa,理由是new B()之前會調用static B(),然後new A()之前需要調用static A,這樣結果是aaaa,但是實際情況並非如果,正確的結果是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的靜態建構函式了,因為前面已經調用過了,靜態函數在整個應用程式定義域的生命週期中只會調用一次!
請大家多指教啊!
類的靜態建構函式也叫類型構造器,靜態構造器,他調用的時刻由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";
}
}
大家猜猜輸出結果是什麼,可能有人認為會輸出aaaa,理由是new B()之前會調用static B(),然後new A()之前需要調用static A,這樣結果是aaaa,但是實際情況並非如果,正確的結果是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的靜態建構函式了,因為前面已經調用過了,靜態函數在整個應用程式定義域的生命週期中只會調用一次!
請大家多指教啊!