静态类和静态类成员(C# 编程指南)
Visual Studio 2015
靜態類與非靜態類基本相同,但存在一個區別:靜態類不能實例化。也就是說,不能使用 new 關鍵字創建靜態類類型的變量。因為沒有實例變量,所以要使用類名本身訪問靜態類的成員。例如,如果名為 UtilityClass 的靜態類有一個名為 MethodA 的公共方法,則按下面的示例所示調用該方法:
UtilityClass.MethodA();
對于只對輸入參數進行運算而不獲取或設置任何內部實例字段的方法集,靜態類可以方便地用作這些方法集的容器。例如,在 .NET Framework 類庫中,靜態類System.Math 包含的方法只執行數學運算,而無需存儲或檢索特定 Math 類實例特有的數據。就是說,通過指定類名稱和方法名稱來應用類成員,如下示例所述。
double dub = -3.14; Console.WriteLine(Math.Abs(dub)); Console.WriteLine(Math.Floor(dub)); Console.WriteLine(Math.Round(Math.Abs(dub))); // Output: // 3.14 // -4 // 3
和所有類類型一樣,當加載引用靜態類的程序時,.NET Framework 公共語言運行時 (CLR) 將加載該靜態類的類型信息。程序不能指定加載靜態類的確切時間。但是,可以保證在程序中首次引用該類前加載該類,并初始化該類的字段并調用其靜態構造函數。靜態構造函數僅調用一次,在程序駐留的應用程序域的生存期內,靜態類一直保留在內存中。
![]() |
---|
若要創建僅允許創建一個自身實例的非靜態類,請參見 Implementing Singleton in C#(在 C# 中實現單一實例)。 |
下表介紹靜態類的主要特性:
-
僅包含靜態成員。
-
無法實例化。
-
是密封的。
-
不能包含實例構造函數。
因此,創建靜態類與創建僅包含靜態成員和私有構造函數的類基本相同。私有構造函數阻止類被實例化。使用靜態類的優點在于,編譯器能夠執行檢查以確保不致偶然地添加實例成員。編譯器將保證不會創建此類的實例。
靜態類是密封的,因此不可被繼承。它們不能從除 Object 外的任何類中繼承。靜態類不能包含實例構造函數,但可以包含靜態構造函數。如果非靜態類包含需要進行重要的初始化的靜態成員,也應定義靜態構造函數。有關更多信息,請參見 靜態構造函數(C# 編程指南)。
下面是一個靜態類的示例,它包含兩個在攝氏溫度和華氏溫度之間執行來回轉換的方法:
public static class TemperatureConverter { public static double CelsiusToFahrenheit(string temperatureCelsius) { // Convert argument to double for calculations. double celsius = Double.Parse(temperatureCelsius); // Convert Celsius to Fahrenheit. double fahrenheit = (celsius * 9 / 5) + 32; return fahrenheit; } public static double FahrenheitToCelsius(string temperatureFahrenheit) { // Convert argument to double for calculations. double fahrenheit = Double.Parse(temperatureFahrenheit); // Convert Fahrenheit to Celsius. double celsius = (fahrenheit - 32) * 5 / 9; return celsius; } } class TestTemperatureConverter { static void Main() { Console.WriteLine("Please select the convertor direction"); Console.WriteLine("1. From Celsius to Fahrenheit."); Console.WriteLine("2. From Fahrenheit to Celsius."); Console.Write(":"); string selection = Console.ReadLine(); double F, C = 0; switch (selection) { case "1": Console.Write("Please enter the Celsius temperature: "); F = TemperatureConverter.CelsiusToFahrenheit(Console.ReadLine()); Console.WriteLine("Temperature in Fahrenheit: {0:F2}", F); break; case "2": Console.Write("Please enter the Fahrenheit temperature: "); C = TemperatureConverter.FahrenheitToCelsius(Console.ReadLine()); Console.WriteLine("Temperature in Celsius: {0:F2}", C); break; default: Console.WriteLine("Please select a convertor."); break; } // Keep the console window open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } } /* Example Output: Please select the convertor direction 1. From Celsius to Fahrenheit. 2. From Fahrenheit to Celsius. :2 Please enter the Fahrenheit temperature: 20 Temperature in Celsius: -6.67 Press any key to exit. */
非靜態類可以包含靜態的方法、字段、屬性或事件。即使沒有創建類的實例,也可以調用該類中的靜態成員。始終通過類名而不是實例名稱訪問靜態成員。無論對一個類創建多少個實例,它的靜態成員都只有一個副本。靜態方法和屬性不能訪問其包含類型中的非靜態字段和事件,并且不能訪問任何對象的實例變量(除非在方法參數中顯式傳遞)。
更常見的做法是聲明具有一些靜態成員的非靜態類,而不是將整個類聲明為靜態類。靜態字段有兩個常見的用法:一是記錄已實例化對象的個數,二是存儲必須在所有實例之間共享的值。
靜態方法可以被重載但不能被重寫,因為它們屬于類,不屬于類的任何實例。
雖然字段不能聲明為 static const,但 const 字段的行為在本質上是靜態的。這樣的字段屬于類型,不屬于類型的實例。因此,可以同對待靜態字段一樣使用 ClassName.MemberName 表示法來訪問 const 字段。不需要對象實例。
C# 不支持靜態局部變量(在方法范圍內聲明的變量)。
通過在成員的返回類型之前使用 static 關鍵字可以聲明靜態類成員,如下面的示例所示:
public class Automobile { public static int NumberOfWheels = 4; public static int SizeOfGasTank { get { return 15; } } public static void Drive() { } public static event EventType RunOutOfGas; // Other non-static fields and properties... }
靜態成員在第一次被訪問之前并且在調用靜態構造函數(如有存在)之前進行初始化。若要訪問靜態類成員,應使用類名而不是變量名來指定該成員的位置,如下面的示例所示:
Automobile.Drive(); int i = Automobile.NumberOfWheels;
如果類包含靜態字段,請提供在加載類時初始化這些字段的靜態構造函數。
對靜態方法的調用以 Microsoft 中間語言 (MSIL) 生成調用指令,而對實例方法的調用生成 callvirt 指令,該指令還檢查 null 對象引用。但是,兩者之間的性能差異在大多數時候并不明顯。
有關詳細信息,請參閱 C# 語言規范。該語言規范是 C# 語法和用法的權威資料。