當一個字段聲明中含有
static
修飾符時,由該聲明引入的字段為靜態字段(靜態變量)。當不存在
static
修飾符時,由該聲明引入的字段為實例字段(實例變量)。
靜態字段不屬於某個特定的實例;相反,它只標識了一個存儲位置。不管創建了多少個類實例,對於關聯的應用程序域來說,在任何時候靜態字段都只會有一個副本。實例字段屬於某個實例。具體說來,類的每個實例都包含了該類的所有實例字段的一個單獨的集合。
(2)字段聲明可以包含變量初始值設定項,兩者初始化區別如下:
對於靜態字段,變量初始值設定項相當於在類初始化期間執行的賦值語句。
對於實例字段,變量初始值設定項相當於創建類的實例時執行的賦值語句。
示例如下:
using System; class Test { static double x = Math.Sqrt(2.0); int i = 100; string s = "Hello"; static void Main() { Test a = new Test(); Console.WriteLine("x = {0}, i = {1}, s = {2}", x, a.i, a.s); } }
產生輸出:
x = 1.4142135623731, i = 100, s = Hello
這是因為對 x
的賦值發生在靜態字段初始值設定項執行時,而對 i
和 s
的賦值發生在實例字段初始值設定項執行時。
(3)類的靜態字段變量初始值設定項對應於一個賦值序列,這些賦值按照它們在相關的類聲明中出現的文本順序執行。如果類中存在靜態構造函數,則靜態字段初始值設定項的執行在該靜態構造函數即將執行前發生。否則,靜態字段初始值設定項在第一次使用該類的靜態字段之前先被執行,但實際執行時間依賴於具體的實現。
如下示例:
using System; class Test { static void Main() { Console.WriteLine("{0} {1}", B.Y, A.X); } public static int F(string s) { Console.WriteLine(s); return 1; } } class A { public static int X = Test.F("Init A"); } class B { public static int Y = Test.F("Init B"); }
或產生輸出
Init B Init A 1 1
這是因為 X
的初始值設定項和 Y
的初始值設定項的執行順序無法預先確定,上述兩種順序都有可能發生;唯一能夠確定的是:它們一定會在對那些字段的引用之前發生。但是,下面的示例:
using System; class Test { static void Main() { Console.WriteLine("{0} {1}", B.Y, A.X); } public static int F(string s) { Console.WriteLine(s); return 1; } } class A { static A() {} public static int X = Test.F("Init A"); } class B { static B() {} public static int Y = Test.F("Init B"); }
所產生的輸出必然是:
Init B Init A 1 1
這是因為關於何時執行靜態構造函數的規則(在第 10.11 節中定義)規定:B
的靜態構造函數(以及 B
的靜態字段初始值設定項)必須在 A
的靜態構造函數和字段初始值設定項之前運行。