靜態類別和靜態類別成員 (C# 程式設計手冊)

static 類別基本上與非靜態類別相同,但有一項差異︰無法具現化靜態類別。 換句話說,您不能使用 new 運算子來建立類別型別的變數。 因為沒有任何執行個體變數,所以您可以使用類別名稱本身來存取靜態類別的成員。 例如,如果您的 UtilityClass 靜態類別包含 MethodA 公用靜態方法,則會呼叫方法,如下列範例所示︰

UtilityClass.MethodA();

如果方法集只作業於輸入參數,並且不需要取得或設定任何內部執行個體欄位,則靜態類別可以用作其方便使用的容器。 例如,在 .NET 類別庫中,靜態 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 執行階段會載入靜態類別的型別資訊。 程式無法指定確實載入類別的時間。 不過,一定會載入類別、初始化其欄位,並在第一次於程式中參考類別之前呼叫其靜態建構函式。 只會呼叫靜態建構函式一次,而且靜態類別在程式所在應用程式定義域的存留期間保留在記憶體中。

注意

若要建立只允許建立它本身之一個執行個體的非靜態類別,請參閱 Implementing Singleton in C# (在 C# 中實作單一)。

下列清單提供靜態類別的主要功能︰

因此,建立靜態類別,基本上與建立只包含靜態成員和私用建構函式的類別相同。 私用建構函式可防止具現化類別。 使用靜態類別的優點在於編譯器可以確認不會意外新增任何執行個體成員。 編譯器可保證此類別的執行個體不會建立。

靜態類別已密封,因此無法進行繼承。 它們無法繼承自 Object 以外的任何類別或介面。 靜態類別不能包含執行個體建構函式。 不過,它們可以包含靜態建構函式。 如果類別包含需要重要初始化的靜態成員,則非靜態類別也應該定義靜態建構函式。 如需詳細資訊,請參閱靜態建構函式

範例

以下是包含兩種方法可將溫度從攝氏轉換為華氏以及從華氏轉換為攝氏的靜態類別範例:

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() ?? "0");
                Console.WriteLine("Temperature in Fahrenheit: {0:F2}", F);
                break;

            case "2":
                Console.Write("Please enter the Fahrenheit temperature: ");
                C = TemperatureConverter.FahrenheitToCelsius(Console.ReadLine() ?? "0");
                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;

如果您的類別包含靜態欄位,請提供在載入類別時初始化它們的靜態建構函式。

靜態方法的呼叫會使用通用中間語言 (CIL) 產生呼叫指令,而執行個體方法的呼叫會產生 callvirt 指令,這也會檢查是否有 Null 物件參考。 不過,大部分的時間,兩者之間的效能差異並不明顯。

C# 語言規格

如需詳細資訊,請參閱 C# 語言規格中的靜態類別靜態和執行個體的成員靜態建構函式。 語言規格是 C# 語法及用法的限定來源。

另請參閱