閱讀英文

共用方式為


System.Enum 類別

本文提供此 API 參考文件的補充備註。

列舉是一組具名常數,其基礎類型為任何整數類型。 如果未明確宣告基礎類型, Int32 則會使用 。 Enum 是 .NET 中所有列舉的基類。 列舉類型是由 enum C# 中的 關鍵詞、 EnumVisual Basic 中的 ...End Enum 建構和 type F# 中的 關鍵詞所定義。

Enum 提供方法來比較這個類別的實例、將實例的值轉換為其字串表示法、將數位的字串表示轉換為這個類別的實例,以及建立指定列舉和值的實例。

您也可以將列舉視為位欄位。 如需詳細資訊,請參閱 非獨佔成員和 Flags 屬性 一節和 FlagsAttribute

建立列舉類型

程序設計語言通常會提供語法來宣告列舉,其中包含一組具名常數及其值。 下列範例說明 C#、F# 和 Visual Basic 用來定義列舉的語法。 它會建立名為 ArrivalStatus 的列舉,其具有三個成員: ArrivalStatus.EarlyArrivalStatus.OnTimeArrivalStatus.Late。 請注意,在所有情況下,列舉不會明確繼承自 Enum;繼承關聯性是由編譯程式隱含處理。

C#
public enum ArrivalStatus { Unknown=-3, Late=-1, OnTime=0, Early=1 };

警告

您絕對不應該建立其基礎型別為非整數或 Char的列舉型別。 雖然您可以使用反映來建立這類列舉型別,但使用所產生型別的方法呼叫並不可靠,也可能會擲回其他例外狀況。

具現化列舉類型

您可以宣告變數,並將其中一個列舉常數指派給它,來具現化列舉類型,就像具現化任何其他實值類型一樣。 下列範例會具現化 ArrivalStatus 其值為 ArrivalStatus.OnTime的 。

C#
public class Example
{
   public static void Main()
   {
      ArrivalStatus status = ArrivalStatus.OnTime;
      Console.WriteLine("Arrival Status: {0} ({0:D})", status);
   }
}
// The example displays the following output:
//       Arrival Status: OnTime (0)

您也可以使用下列方式具現化列舉值:

  • 藉由使用特定程式設計語言的功能,將整數值轉換成列舉值(如 C#中所示),或將整數值轉換為列舉值。 下列範例會 ArrivalStatus 建立物件,其值 ArrivalStatus.Early 是以此方式。

    C#
    ArrivalStatus status2 = (ArrivalStatus)1;
    Console.WriteLine("Arrival Status: {0} ({0:D})", status2);
    // The example displays the following output:
    //       Arrival Status: Early (1)
    
  • 藉由呼叫其隱含無參數建構函式。 如下列範例所示,在此情況下,列舉實例的基礎值為0。 不過,這不一定是列舉中有效常數的值。

    C#
    ArrivalStatus status1 = new ArrivalStatus();
    Console.WriteLine("Arrival Status: {0} ({0:D})", status1);
    // The example displays the following output:
    //       Arrival Status: OnTime (0)
    
  • 藉由呼叫 ParseTryParse 方法來剖析包含列舉中常數名稱的字串。 如需詳細資訊,請參閱 剖析列舉值 一節。

  • 藉由呼叫 ToObject 方法,將整數值轉換成列舉型別。 如需詳細資訊,請參閱 執行轉換 一節。

列舉最佳做法

當您定義列舉類型時,建議您使用下列最佳做法:

  • 如果您尚未定義值為 0 的列舉成員,請考慮建立 None 列舉常數。 根據預設,用於列舉的記憶體會由 Common Language Runtime 初始化為零。 因此,如果您未定義值為零的常數,列舉會在建立時包含不合法的值。

  • 如果應用程式必須表示的明顯預設案例,請考慮使用列舉常數,其值為零來表示它。 如果沒有預設案例,請考慮使用列舉常數,其值為零的列舉常數來指定任何其他列舉常數未表示的案例。

  • 請勿指定保留供日後使用的列舉常數。

  • 當您定義接受列舉常數做為值的方法或屬性時,請考慮驗證值。 原因是即使列舉中未定義數值,您也可以將數值轉換成列舉類型。

列舉型別的其他最佳做法,其常數是位欄位欄位列在 非獨佔成員和 Flags 屬性 區段中。

使用列舉執行作業

當您建立列舉時,無法定義新的方法。 不過,列舉型別會從 Enum 類別繼承一組完整的靜態和實例方法。 下列各節除了使用列舉值時常用的數個其他方法之外,也會調查這些方法中的大部分。

執行轉換

您可以在列舉成員與其基礎類型之間轉換,方法是使用轉換 (在 C# 和 F# 中),或轉換 (在 Visual Basic 中) 運算子。 在 F# 中,也會使用 函 enum 式。 下列範例使用轉換或轉換運算符來執行從整數到列舉值,以及從列舉值轉換為整數的轉換。

C#
int value3 = 2;
ArrivalStatus status3 = (ArrivalStatus)value3;

int value4 = (int)status3;

類別 Enum 也包含 ToObject 方法,可將任何整數型別的值轉換成列舉值。 下列範例會使用 ToObject(Type, Int32) 方法,將轉換成 Int32ArrivalStatus 值。 請注意,由於會 ToObject 傳回 型 Object別的值,因此使用轉換或轉換運算符仍可能需要將對象轉換成列舉型別。

C#
int number = -1;
ArrivalStatus arrived = (ArrivalStatus)ArrivalStatus.ToObject(typeof(ArrivalStatus), number);

將整數轉換成列舉值時,可以指派不是列舉成員的值。 若要避免這種情況,您可以先將整數傳遞至 IsDefined 方法,再執行轉換。 下列範例會使用這個方法來判斷整數值陣列中的元素是否可以轉換成 ArrivalStatus 值。

C#
using System;

public class Example3
{
    public static void Main()
    {
        int[] values = { -3, -1, 0, 1, 5, Int32.MaxValue };
        foreach (var value in values)
        {
            ArrivalStatus status;
            if (Enum.IsDefined(typeof(ArrivalStatus), value))
                status = (ArrivalStatus)value;
            else
                status = ArrivalStatus.Unknown;
            Console.WriteLine("Converted {0:N0} to {1}", value, status);
        }
    }
}
// The example displays the following output:
//       Converted -3 to Unknown
//       Converted -1 to Late
//       Converted 0 to OnTime
//       Converted 1 to Early
//       Converted 5 to Unknown
//       Converted 2,147,483,647 to Unknown

雖然 類別 Enum 會提供介面的 IConvertible 明確介面實作,以便從列舉值轉換成整數型別,但您應該使用 類別的方法 Convert ,例如 ToInt32,來執行這些轉換。 下列範例說明如何使用 GetUnderlyingType 方法以及 Convert.ChangeType 方法,將列舉值轉換成其基礎類型。 請注意,此範例不需要在編譯時期知道列舉的基礎類型。

C#
ArrivalStatus status = ArrivalStatus.Early;
var number = Convert.ChangeType(status, Enum.GetUnderlyingType(typeof(ArrivalStatus)));
Console.WriteLine("Converted {0} to {1}", status, number);
// The example displays the following output:
//       Converted Early to 1

剖析列舉值

ParseTryParse 方法可讓您將列舉值的字串表示轉換成該值。 字串表示可以是列舉常數的名稱或基礎值。 請注意,如果字串可以轉換成列舉基礎類型的值,剖析方法將成功轉換不是特定列舉成員之數位的字串表示。 若要避免這種情況, IsDefined 可以呼叫 方法,以確保剖析方法的結果是有效的列舉值。 此範例說明此方法,並示範對 Parse(Type, String)Enum.TryParse<TEnum>(String, TEnum) 方法的呼叫。 請注意,非泛型剖析方法會傳回您可能必須轉換的物件(在 C# 和 F# 中),或將 (在 Visual Basic 中) 轉換為適當的列舉類型。

C#
string number = "-1";
string name = "Early";

try
{
    ArrivalStatus status1 = (ArrivalStatus)Enum.Parse(typeof(ArrivalStatus), number);
    if (!(Enum.IsDefined(typeof(ArrivalStatus), status1)))
        status1 = ArrivalStatus.Unknown;
    Console.WriteLine("Converted '{0}' to {1}", number, status1);
}
catch (FormatException)
{
    Console.WriteLine("Unable to convert '{0}' to an ArrivalStatus value.",
                      number);
}

ArrivalStatus status2;
if (Enum.TryParse<ArrivalStatus>(name, out status2))
{
    if (!(Enum.IsDefined(typeof(ArrivalStatus), status2)))
        status2 = ArrivalStatus.Unknown;
    Console.WriteLine("Converted '{0}' to {1}", name, status2);
}
else
{
    Console.WriteLine("Unable to convert '{0}' to an ArrivalStatus value.",
                      number);
}
// The example displays the following output:
//       Converted '-1' to Late
//       Converted 'Early' to Early

格式化列舉值

您可以呼叫靜態 Format 方法,以及實例 ToString 方法的多載,將列舉值轉換成其字串表示法。 您可以使用格式字串來控制列舉值以字串表示的精確方式。 如需詳細資訊,請參閱 列舉格式字串。 下列範例會使用每個支援的列舉格式字串 (“G” 或 “g”、“D” 或 “d”、“X” 或 “x” 和 “F” 或 “f” 將列舉的成員 ArrivalStatus 轉換成其字串表示法。

C#
string[] formats = { "G", "F", "D", "X" };
ArrivalStatus status = ArrivalStatus.Late;
foreach (var fmt in formats)
    Console.WriteLine(status.ToString(fmt));

// The example displays the following output:
//       Late
//       Late
//       -1
//       FFFFFFFF

逐一查看列舉成員

類型 Enum 不會實 IEnumerable 作 或 IEnumerable<T> 介面,這可讓您使用 foreach (在 C# 中)、 (在 F# 中) for..inFor Each (在 Visual Basic) 建構中逐一查看集合的成員。 不過,您可以透過兩種方式之一列舉成員。

  • 您可以呼叫 GetNames 方法來擷取包含列舉成員名稱的字串數位。 接下來,針對字串陣列的每個元素,您可以呼叫 Parse 方法,將字元串轉換成其相等的列舉值。 下列範例將示範這個方法。

    C#
    string[] names = Enum.GetNames(typeof(ArrivalStatus));
    Console.WriteLine("Members of {0}:", typeof(ArrivalStatus).Name);
    Array.Sort(names);
    foreach (var name in names)
    {
        ArrivalStatus status = (ArrivalStatus)Enum.Parse(typeof(ArrivalStatus), name);
        Console.WriteLine("   {0} ({0:D})", status);
    }
    // The example displays the following output:
    //       Members of ArrivalStatus:
    //          Early (1)
    //          Late (-1)
    //          OnTime (0)
    //          Unknown (-3)
    
  • 您可以呼叫 GetValues 方法來擷取陣列,其中包含列舉中的基礎值。 接下來,針對陣列的每個元素,您可以呼叫 ToObject 方法,將整數轉換成其相等的列舉值。 下列範例將示範這個方法。

    C#
    var values = Enum.GetValues(typeof(ArrivalStatus));
    Console.WriteLine("Members of {0}:", typeof(ArrivalStatus).Name);
    foreach (ArrivalStatus status in values)
    {
        Console.WriteLine("   {0} ({0:D})", status);
    }
    // The example displays the following output:
    //       Members of ArrivalStatus:
    //          OnTime (0)
    //          Early (1)
    //          Unknown (-3)
    //          Late (-1)
    

非獨佔成員和 Flags 屬性

列舉的一個常見用法是表示一組互斥值。 例如, ArrivalStatus 實體的值可以是 EarlyOnTimeLate。 實例的值 ArrivalStatus 無法反映一個以上的列舉常數。

不過,在其他情況下,列舉物件的值可以包含多個列舉成員,而且每個成員都代表列舉值中的位字段。 FlagsAttribute屬性可用來指出列舉是由位欄位所組成。 例如,名為 Pets 的列舉可用來指出家庭中的寵物種類。 其定義方式如下。

C#
[Flags]
public enum Pets
{
    None = 0, Dog = 1, Cat = 2, Bird = 4, Rodent = 8,
    Reptile = 16, Other = 32
};

Pets然後,可以使用 列舉,如下列範例所示。

C#
Pets familyPets = Pets.Dog | Pets.Cat;
Console.WriteLine("Pets: {0:G} ({0:D})", familyPets);
// The example displays the following output:
//       Pets: Dog, Cat (3)

定義位列舉並套用 FlagsAttribute 屬性時,應該使用下列最佳做法。

  • FlagsAttribute只有在要對數值執行位運算(AND、OR、EXCLUSIVE OR)時,才使用列舉的自定義屬性。

  • 定義兩個乘冪的列舉常數,也就是 1、2、4、8 等等。 這表示合並列舉常數中的個別旗標不會重疊。

  • 請考慮為常用的旗標組合建立列舉常數。 例如,如果您有用於包含列舉常數和 Write = 2的檔案 I/O 作業的列舉,請考慮建立列舉常數 Read = 1ReadWrite = Read OR Write,這會結合 ReadWrite 旗標。 此外,在某些情況下,用來結合旗標的位 OR 作業可能會被視為一個進階概念,而不需要簡單的工作。

  • 如果您將負數定義為旗標列舉常數,請小心,因為許多旗標位置可能設定為 1,這可能會導致程式代碼混淆並鼓勵編碼錯誤。

  • 測試數值中是否設定旗標的便利方式是呼叫 實例 HasFlag 方法,如下列範例所示。

    C#
    Pets familyPets = Pets.Dog | Pets.Cat;
    if (familyPets.HasFlag(Pets.Dog))
        Console.WriteLine("The family has a dog.");
    // The example displays the following output:
    //       The family has a dog.
    

    它相當於在數值與旗標列舉常數之間執行位 AND 運算,它會將數值中的所有位設定為零,但不會對應至旗標,然後測試該作業的結果是否等於旗標列舉常數。 下列範例會加以說明。

    C#
    Pets familyPets = Pets.Dog | Pets.Cat;
    if ((familyPets & Pets.Dog) == Pets.Dog)
        Console.WriteLine("The family has a dog.");
    // The example displays the following output:
    //       The family has a dog.
    
  • 使用 None 做為旗標列舉常數的名稱,其值為零。 您無法在 None 位 AND 作業中使用列舉常數來測試旗標,因為結果一律為零。 不過,您可以執行數值與 None 列舉常數之間的邏輯而非位比較,以判斷數值中的任何位是否已設定。 下列範例會加以說明。

    C#
    Pets familyPets = Pets.Dog | Pets.Cat;
    if (familyPets == Pets.None)
        Console.WriteLine("The family has no pets.");
    else
        Console.WriteLine("The family has pets.");
    // The example displays the following output:
    //       The family has pets.
    
  • 請勿只定義列舉值,以鏡像列舉本身的狀態。 例如,請勿定義只標記列舉結尾的列舉常數。 如果您需要判斷列舉的最後一個值,請明確檢查該值。 此外,如果範圍內的所有值都有效,您可以針對第一個和最後一個列舉常數執行範圍檢查。

新增列舉方法

因為列舉型別是由語言結構所定義,例如 enum (C#) 和 Enum (Visual Basic),所以您無法定義列舉型別的自定義方法,而不是繼承自 Enum 類別的方法。 不過,您可以使用擴充方法將功能新增至特定列舉類型。

在下例中,Grades 列舉代表班上學生可能得到的字母分級成績。 已將名為 Passing 的擴充方法新增至 Grades 類型,以便該類型的每個執行個體現在都「知道」它是否代表傳遞等級。 類別 Extensions 也包含靜態讀寫變數,可定義最低通過等級。 擴充方法的 Passing 傳回值會反映該變數的目前值。

C#
using System;

// Define an enumeration to represent student grades.
public enum Grades { F = 0, D = 1, C = 2, B = 3, A = 4 };

// Define an extension method for the Grades enumeration.
public static class Extensions
{
    public static Grades minPassing = Grades.D;

    public static bool Passing(this Grades grade)
    {
        return grade >= minPassing;
    }
}

class Example8
{
    static void Main()
    {
        Grades g1 = Grades.D;
        Grades g2 = Grades.F;
        Console.WriteLine("{0} {1} a passing grade.", g1, g1.Passing() ? "is" : "is not");
        Console.WriteLine("{0} {1} a passing grade.", g2, g2.Passing() ? "is" : "is not");

        Extensions.minPassing = Grades.C;
        Console.WriteLine("\nRaising the bar!\n");
        Console.WriteLine("{0} {1} a passing grade.", g1, g1.Passing() ? "is" : "is not");
        Console.WriteLine("{0} {1} a passing grade.", g2, g2.Passing() ? "is" : "is not");
    }
}
// The exmaple displays the following output:
//       D is a passing grade.
//       F is not a passing grade.
//
//       Raising the bar!
//
//       D is not a passing grade.
//       F is not a passing grade.

範例

下列範例示範如何使用 列舉來表示具名值,以及另一個列舉來表示具名位字段。

C#
using System;

public class EnumTest {
    enum Days { Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday };
    enum BoilingPoints { Celsius = 100, Fahrenheit = 212 };
    [Flags]
    enum Colors { Red = 1, Green = 2, Blue = 4, Yellow = 8 };

    public static void Main() {

        Type weekdays = typeof(Days);
        Type boiling = typeof(BoilingPoints);

        Console.WriteLine("The days of the week, and their corresponding values in the Days Enum are:");

        foreach ( string s in Enum.GetNames(weekdays) )
            Console.WriteLine( "{0,-11}= {1}", s, Enum.Format( weekdays, Enum.Parse(weekdays, s), "d"));

        Console.WriteLine();
        Console.WriteLine("Enums can also be created which have values that represent some meaningful amount.");
        Console.WriteLine("The BoilingPoints Enum defines the following items, and corresponding values:");

        foreach ( string s in Enum.GetNames(boiling) )
            Console.WriteLine( "{0,-11}= {1}", s, Enum.Format(boiling, Enum.Parse(boiling, s), "d"));

        Colors myColors = Colors.Red | Colors.Blue | Colors.Yellow;
        Console.WriteLine();
        Console.WriteLine("myColors holds a combination of colors. Namely: {0}", myColors);
    }
}