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

靜態類別基本上跟非靜態類別相同,但有一個差別:靜態類別不能具現化 (Instantiated)。 換句話說,您不能使用 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 Common Language Runtime (CLR) 在載入參考該類別的程式時載入。程式無法確實指定何時載入類別。 然而,類別卻能保證一定會載入,並會在您的程式第一次參考此類別前,先讓其中的欄位初始化,而其中的靜態建構函式也受到呼叫。 靜態建構函式只會受到一次呼叫,而後在您程式所在的應用程式定義域的存留期 (Lifetime) 中,都會在記憶體中保留靜態類別。

注意事項注意事項

若要建立一個非靜態類別,僅允許為其本身建立一個執行個體,請參閱在 C# 中實作單一類別 (英文)。

下列清單會提供靜態類別的主要特色:

因此基本上,建立靜態類別就是建立只包含靜態成員和私用建構函式 (Private Constructor) 的類別。 私用建構函式可讓類別避免執行個體化。 使用靜態類別的好處是,編譯器可進行檢查,確定不會在不小心的情況下加入執行個體成員。 編譯器將可確保這個類別不會建立執行個體。

靜態類別是密封的,因此無法繼承。 它們不能繼承自 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 欄位的行為基本上是靜態的, 屬於型別,而非型別的執行個體。 因此,const 欄位可透過用於靜態欄位的相同 ClassName.MemberName 標記法存取, 不需要任何物件執行個體。

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 Intermediate Language (MSIL) 中產生呼叫指令,同時對執行個體方法的呼叫會產生 callvirt 指令,並會檢查 null 物件參考。 然而在大部分情況中,這兩者之間的效能差異並不顯著。

C# 語言規格

如需詳細資訊,請參閱 C# 語言規格。 語言規格是 C# 語法和用法的決定性來源。

請參閱

參考

static (C# 參考)

類別 (C# 程式設計手冊)

類別 (C# 參考)

靜態建構函式 (C# 程式設計手冊)

執行個體建構函式 (C# 程式設計手冊)

概念

C# 程式設計手冊

靜態類別設計