System.Enum, klasa

Ten artykuł zawiera dodatkowe uwagi dotyczące dokumentacji referencyjnej dla tego interfejsu API.

Wyliczenie jest zestawem nazwanych stałych, których typ bazowy jest dowolnym typem całkowitym. Jeśli żaden typ bazowy nie jest jawnie zadeklarowany, Int32 jest używany. Enum jest klasą bazową dla wszystkich wyliczeń na platformie .NET. Typy wyliczenia są definiowane przez enum słowo kluczowe w języku C#, konstrukcję Enum...End Enum w Visual Basic i type słowo kluczowe w języku F#.

Enum Udostępnia metody porównywania wystąpień tej klasy, konwertowania wartości wystąpienia na reprezentację ciągu, konwertowanie reprezentacji ciągu liczby na wystąpienie tej klasy oraz tworzenie wystąpienia określonej wyliczenia i wartości.

Można również traktować wyliczenie jako pole bitowe. Aby uzyskać więcej informacji, zobacz sekcję Nie wykluczające się elementy członkowskie oraz sekcję atrybutu Flags i FlagsAttribute.

Tworzenie typu wyliczenia

Języki programowania zwykle zapewniają składnię do deklarowania wyliczenia składającego się z zestawu nazwanych stałych i ich wartości. Poniższy przykład ilustruje składnię używaną przez język C#, F# i Visual Basic do zdefiniowania wyliczenia. Tworzy wyliczenie o nazwie ArrivalStatus zawierającej trzy elementy członkowskie: ArrivalStatus.Early, ArrivalStatus.OnTimei ArrivalStatus.Late. Należy pamiętać, że we wszystkich przypadkach wyliczenie nie dziedziczy jawnie z Enum; relacja dziedziczenia jest obsługiwana niejawnie przez kompilator.

public enum ArrivalStatus { Unknown=-3, Late=-1, OnTime=0, Early=1 };
type ArrivalStatus =
    | Late = -1
    | OnTime = 0
    | Early = 1
Public Enum ArrivalStatus1 As Integer
    Late = -1
    OnTime = 0
    Early = 1
End Enum

Ostrzeżenie

Nigdy nie należy tworzyć typu wyliczenia, którego typ bazowy nie jest całkowity lub Char. Chociaż można utworzyć taki typ wyliczenia przy użyciu odbicia, wywołania metod używające wynikowego typu są zawodne i mogą również zgłaszać dodatkowe wyjątki.

Tworzenie wystąpienia typu wyliczenia

Możesz utworzyć wystąpienie typu wyliczenia tak samo, jak wystąpienie dowolnego innego typu wartości: deklarując zmienną i przypisując do niej jedną z stałych wyliczenia. Poniższy przykład tworzy wystąpienie, ArrivalStatus którego wartość to ArrivalStatus.OnTime.

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)
let status = ArrivalStatus.OnTime
printfn $"Arrival Status: {status} ({status:D})"
// The example displays the following output:
//       Arrival Status: OnTime (0)
Public Module Example1
    Public Sub Main()
        Dim status As ArrivalStatus1 = ArrivalStatus1.OnTime
        Console.WriteLine("Arrival Status: {0} ({0:D})", status)
    End Sub
End Module
' The example displays the following output:
'        Arrival Status: OnTime (0)

Możesz również utworzyć wystąpienie wartości wyliczenia w następujący sposób:

  • Używając funkcji określonego języka programowania do rzutowania (tak jak w języku C#) lub konwertowania (jak w Visual Basic) wartości całkowitej na wartość wyliczenia. Poniższy przykład tworzy ArrivalStatus obiekt, którego wartość jest ArrivalStatus.Early w ten sposób.

    ArrivalStatus status2 = (ArrivalStatus)1;
    Console.WriteLine("Arrival Status: {0} ({0:D})", status2);
    // The example displays the following output:
    //       Arrival Status: Early (1)
    
    let status2 = enum<ArrivalStatus> 1
    printfn $"Arrival Status: {status2} ({status2:D})"
    // The example displays the following output:
    //       Arrival Status: Early (1)
    
    Dim status2 As ArrivalStatus2 = CType(1, ArrivalStatus2)
    Console.WriteLine("Arrival Status: {0} ({0:D})", status2)
    ' The example displays the following output:
    '       Arrival Status: Early (1)
    
  • Wywołując niejawny konstruktor bez parametrów. Jak pokazano w poniższym przykładzie, w tym przypadku podstawowa wartość wystąpienia wyliczenia wynosi 0. Jednak niekoniecznie jest to wartość prawidłowej stałej w wyliczenie.

    ArrivalStatus status1 = new ArrivalStatus();
    Console.WriteLine("Arrival Status: {0} ({0:D})", status1);
    // The example displays the following output:
    //       Arrival Status: OnTime (0)
    
    let status1 = ArrivalStatus()
    printfn $"Arrival Status: {status1} ({status1:D})"
    // The example displays the following output:
    //       Arrival Status: OnTime (0)
    
    Dim status1 As New ArrivalStatus2()
    Console.WriteLine("Arrival Status: {0} ({0:D})", status1)
    ' The example displays the following output:
    '        Arrival Status: OnTime (0)
    
  • Wywołując metodę Parse or TryParse , aby przeanalizować ciąg zawierający nazwę stałej w wyliczenie. Aby uzyskać więcej informacji, zobacz sekcję Analizowanie wartości wyliczenia.

  • Wywołując metodę ToObject w celu przekonwertowania wartości całkowitej na typ wyliczenia. Aby uzyskać więcej informacji, zobacz sekcję Wykonywanie konwersji .

Najlepsze rozwiązania dotyczące wyliczania

Zalecamy użycie następujących najlepszych rozwiązań podczas definiowania typów wyliczenia:

  • Jeśli nie zdefiniowano elementu członkowskiego wyliczenia, którego wartość wynosi 0, rozważ utworzenie stałej None wyliczanej. Domyślnie pamięć używana do wyliczania jest inicjowana do zera przez środowisko uruchomieniowe języka wspólnego. W związku z tym jeśli nie zdefiniujesz stałej, której wartość jest równa zero, wyliczenie będzie zawierać niedozwoloną wartość podczas jej tworzenia.

  • Jeśli istnieje oczywisty przypadek domyślny, który aplikacja musi reprezentować, rozważ użycie wyliczonej stałej, której wartość jest równa zero, aby ją reprezentować. Jeśli nie ma przypadku domyślnego, rozważ użycie stałej wyliczonej, której wartość to zero, aby określić przypadek, który nie jest reprezentowany przez żadną z pozostałych wyliczonych stałych.

  • Nie należy określać wyliczonych stałych zarezerwowanych do użytku w przyszłości.

  • Podczas definiowania metody lub właściwości, która przyjmuje wyliczonej stałej jako wartość, rozważ zweryfikowanie wartości. Przyczyną jest możliwość rzutowania wartości liczbowej na typ wyliczenia, nawet jeśli ta wartość liczbowa nie jest zdefiniowana w wyliczeniem.

Dodatkowe najlepsze rozwiązania dotyczące typów wyliczenia, których stałe są polami bitowymi, są wymienione w sekcji Elementy członkowskie bez wykluczania i Atrybut Flags.

Wykonywanie operacji przy użyciu wyliczeń

Podczas tworzenia wyliczenia nie można definiować nowych metod. Jednak typ wyliczenia dziedziczy pełny zestaw metod statycznych i wystąpień z Enum klasy . W poniższych sekcjach przedstawiono większość tych metod, oprócz kilku innych metod, które są często używane podczas pracy z wartościami wyliczenia.

Wykonywanie konwersji

Można przekonwertować między elementem członkowskim wyliczenia i jego typem bazowym przy użyciu operatora rzutowania (w języku C# i F#) lub konwersji (w Visual Basic). W języku enum F#funkcja jest również używana. W poniższym przykładzie użyto operatorów rzutowania lub konwersji, aby wykonać konwersje zarówno z liczby całkowitej, jak i z wartości wyliczenia do liczby całkowitej.

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

int value4 = (int)status3;
let value3 = 2
let status3 = enum<ArrivalStatus> value3

let value4 = int status3
Dim value3 As Integer = 2
Dim status3 As ArrivalStatus2 = CType(value3, ArrivalStatus2)

Dim value4 As Integer = CInt(status3)

Klasa Enum zawiera również metodę ToObject , która konwertuje wartość dowolnego typu całkowitego na wartość wyliczenia. W poniższym przykładzie użyto ToObject(Type, Int32) metody , aby przekonwertować Int32 element na ArrivalStatus wartość. Należy pamiętać, że ponieważ ToObject zwraca wartość typu Object, użycie operatora rzutowania lub konwersji może być nadal konieczne, aby rzutować obiekt na typ wyliczenia.

int number = -1;
ArrivalStatus arrived = (ArrivalStatus)ArrivalStatus.ToObject(typeof(ArrivalStatus), number);
let number = -1
let arrived = ArrivalStatus.ToObject(typeof<ArrivalStatus>, number) :?> ArrivalStatus
Dim number As Integer = -1
Dim arrived As ArrivalStatus2 = CType(ArrivalStatus2.ToObject(GetType(ArrivalStatus2), number), ArrivalStatus2)

Podczas konwertowania liczby całkowitej na wartość wyliczenia można przypisać wartość, która nie jest elementem członkowskim wyliczenia. Aby temu zapobiec, można przekazać liczbę całkowitą do IsDefined metody przed wykonaniem konwersji. W poniższym przykładzie użyto tej metody, aby określić, czy elementy w tablicy wartości całkowitych można przekonwertować na ArrivalStatus wartości.

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
open System

type ArrivalStatus =
    | Unknown = -3
    | Late = -1
    | OnTime = 0
    | Early = 1

let values = [ -3; -1; 0; 1; 5; Int32.MaxValue ]
for value in values do
    let status =
        if Enum.IsDefined(typeof<ArrivalStatus>, value) then
            enum value
        else
            ArrivalStatus.Unknown
    printfn $"Converted {value:N0} to {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
Public Enum ArrivalStatus4 As Integer
    Unknown = -3
    Late = -1
    OnTime = 0
    Early = 1
End Enum

Module Example4
    Public Sub Main()
        Dim values() As Integer = {-3, -1, 0, 1, 5, Int32.MaxValue}
        For Each value In values
            Dim status As ArrivalStatus4
            If [Enum].IsDefined(GetType(ArrivalStatus4), value) Then
                status = CType(value, ArrivalStatus4)
            Else
                status = ArrivalStatus4.Unknown
            End If
            Console.WriteLine("Converted {0:N0} to {1}", value, status)
        Next
    End Sub
End Module
' 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 Mimo że klasa udostępnia jawne implementacje interfejsu interfejsu IConvertible do konwertowania z wartości wyliczenia na typ całkowity, należy użyć metod Convert klasy, takich jak ToInt32, aby wykonać te konwersje. W poniższym przykładzie pokazano, jak można użyć GetUnderlyingType metody wraz z Convert.ChangeType metodą w celu przekonwertowania wartości wyliczenia na jej typ bazowy. Należy pamiętać, że ten przykład nie wymaga, aby podstawowy typ wyliczenia był znany w czasie kompilacji.

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
let status = ArrivalStatus.Early
let number = Convert.ChangeType(status, Enum.GetUnderlyingType typeof<ArrivalStatus>)
printfn $"Converted {status} to {number}"
// The example displays the following output:
//       Converted Early to 1
Dim status As ArrivalStatus5 = ArrivalStatus5.Early
Dim number = Convert.ChangeType(status, [Enum].GetUnderlyingType(GetType(ArrivalStatus5)))
Console.WriteLine("Converted {0} to {1}", status, number)
' The example displays the following output:
'       Converted Early to 1

Analizowanie wartości wyliczenia

Metody Parse i TryParse umożliwiają konwertowanie ciągu reprezentacji wartości wyliczenia na wartość. Reprezentacja ciągu może być nazwą lub podstawową wartością stałej wyliczenia. Należy pamiętać, że metody analizowania zostaną pomyślnie przekonwertowane reprezentacje ciągów liczb, które nie są elementami członkowskimi określonego wyliczenia, jeśli ciągi można przekonwertować na wartość typu bazowego wyliczenia. Aby temu zapobiec, można wywołać metodę w celu upewnienia się, IsDefined że wynik metody analizy jest prawidłową wartością wyliczenia. W przykładzie pokazano to podejście i pokazano wywołania metod Parse(Type, String) i .Enum.TryParse<TEnum>(String, TEnum) Należy pamiętać, że metoda analizowania innego niż ogólna zwraca obiekt, który może być konieczne rzutowanie (w języku C# i F#) lub przekonwertowanie (w Visual Basic) na odpowiedni typ wyliczenia.

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
let number = "-1"
let name = "Early"

try
    let status1 = Enum.Parse(typeof<ArrivalStatus>, number) :?> ArrivalStatus
    let status1 =
        if not (Enum.IsDefined(typeof<ArrivalStatus>, status1) ) then
            ArrivalStatus.Unknown
        else 
            status1
        
    printfn $"Converted '{number}' to {status1}"
with :? FormatException ->
    printfn $"Unable to convert '{number}' to an ArrivalStatus value."

match Enum.TryParse<ArrivalStatus> name with
| true, status2 ->
    let status2 = 
        if not (Enum.IsDefined(typeof<ArrivalStatus>, status2) ) then
            ArrivalStatus.Unknown
        else 
            status2
    printfn $"Converted '{name}' to {status2}"
| _ ->
    printfn $"Unable to convert '{number}' to an ArrivalStatus value."
// The example displays the following output:
//       Converted '-1' to Late
//       Converted 'Early' to Early
Dim number As String = "-1"
Dim name As String = "Early"
Dim invalid As String = "32"

Try
    Dim status1 As ArrivalStatus8 = CType([Enum].Parse(GetType(ArrivalStatus8), number), ArrivalStatus8)
    If Not [Enum].IsDefined(GetType(ArrivalStatus8), status1) Then status1 = ArrivalStatus8.Unknown
    Console.WriteLine("Converted '{0}' to {1}", number, status1)
Catch e As FormatException
    Console.WriteLine("Unable to convert '{0}' to an ArrivalStatus8 value.",
                   number)
End Try

Dim status2 As ArrivalStatus8
If [Enum].TryParse(Of ArrivalStatus8)(name, status2) Then
    If Not [Enum].IsDefined(GetType(ArrivalStatus8), status2) Then status2 = ArrivalStatus8.Unknown
    Console.WriteLine("Converted '{0}' to {1}", name, status2)
Else
    Console.WriteLine("Unable to convert '{0}' to an ArrivalStatus8 value.",
                   number)
End If
' The example displays the following output:
'       Converted '-1' to Late
'       Converted 'Early' to Early

Formatuj wartości wyliczenia

Wartości wyliczenia można przekonwertować na ich reprezentacje ciągów, wywołując metodę statyczną Format , a także przeciążenia metody wystąpienia ToString . Możesz użyć ciągu formatu, aby kontrolować dokładny sposób, w jaki wartość wyliczenia jest reprezentowana jako ciąg. Aby uzyskać więcej informacji, zobacz Ciągi formatu wyliczenia. W poniższym przykładzie użyto każdego z obsługiwanych ciągów formatu wyliczenia ("G" lub "g", "D" lub "d", "X" lub "x" oraz "F" lub "f" ) w celu przekonwertowania elementu członkowskiego ArrivalStatus wyliczenia na jego reprezentacje ciągów.

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
let formats = [ "G"; "F"; "D"; "X" ]
let status = ArrivalStatus.Late
for fmt in formats do
    printfn $"{status.ToString fmt}"

// The example displays the following output:
//       Late
//       Late
//       -1
//       FFFFFFFF
Dim formats() As String = {"G", "F", "D", "X"}
Dim status As ArrivalStatus6 = ArrivalStatus6.Late
For Each fmt As String In formats
    Console.WriteLine(status.ToString(fmt))
Next
' The example displays the following output:
'       Late
'       Late
'       -1
'       FFFFFFFF

Iterowanie elementów członkowskich wyliczania

Typ Enum nie implementuje interfejsu IEnumerable lub IEnumerable<T> , który umożliwia iterowanie elementów członkowskich kolekcji przy użyciu foreach konstrukcji (w języku C#), for..in (w języku F#) ani For Each (w Visual Basic). Można jednak wyliczyć elementy członkowskie na jeden z dwóch sposobów.

  • Metodę GetNames można wywołać, aby pobrać tablicę ciągów zawierającą nazwy elementów członkowskich wyliczenia. Następnie dla każdego elementu tablicy ciągów można wywołać metodę Parse , aby przekonwertować ciąg na równoważną wartość wyliczenia. To podejście pokazano w poniższym przykładzie.

    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)
    
    let names = Enum.GetNames typeof<ArrivalStatus>
    printfn $"Members of {nameof ArrivalStatus}:"
    let names = Array.sort names
    for name in names do
        let status = Enum.Parse(typeof<ArrivalStatus>, name) :?> ArrivalStatus
        printfn $"   {status} ({status:D})"
    // The example displays the following output:
    //       Members of ArrivalStatus:
    //          Early (1)
    //          Late (-1)
    //          OnTime (0)
    //          Unknown (-3)
    
    Dim names() As String = [Enum].GetNames(GetType(ArrivalStatus7))
    Console.WriteLine("Members of {0}:", GetType(ArrivalStatus7).Name)
    Array.Sort(names)
    For Each name In names
        Dim status As ArrivalStatus7 = CType([Enum].Parse(GetType(ArrivalStatus7), name),
                                   ArrivalStatus7)
        Console.WriteLine("   {0} ({0:D})", status)
    Next
    ' The example displays the following output:
    '       Members of ArrivalStatus7:
    '          Early (1)
    '          Late (-1)
    '          OnTime (0)
    '          Unknown (-3)
    
  • Metodę GetValues można wywołać, aby pobrać tablicę zawierającą wartości bazowe w wyliczenie. Następnie dla każdego elementu tablicy można wywołać metodę ToObject , aby przekonwertować liczbę całkowitą na równoważną wartość wyliczenia. To podejście pokazano w poniższym przykładzie.

    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)
    
    let values = Enum.GetValues typeof<ArrivalStatus>
    printfn $"Members of {nameof ArrivalStatus}:"
    for status in values do
        printfn $"   {status} ({status:D})"
    // The example displays the following output:
    //       Members of ArrivalStatus:
    //          OnTime (0)
    //          Early (1)
    //          Unknown (-3)
    //          Late (-1)
    
    Dim values = [Enum].GetValues(GetType(ArrivalStatus7))
    Console.WriteLine("Members of {0}:", GetType(ArrivalStatus7).Name)
    For Each value In values
        Dim status As ArrivalStatus7 = CType([Enum].ToObject(GetType(ArrivalStatus7), value),
                                         ArrivalStatus7)
        Console.WriteLine("   {0} ({0:D})", status)
    Next
    ' The example displays the following output:
    '       Members of ArrivalStatus7:
    '          OnTime (0)
    '          Early (1)
    '          Unknown (-3)
    '          Late (-1)
    

Nie wykluczające się elementy członkowskie i atrybut Flags

Jednym z typowych zastosowań wyliczenia jest reprezentowanie zestawu wzajemnie wykluczających się wartości. Na przykład ArrivalStatus wystąpienie może mieć wartość Early, OnTimelub Late. Nie ma sensu, aby wartość ArrivalStatus wystąpienia odzwierciedlała więcej niż jedną stałą wyliczenia.

W innych przypadkach jednak wartość obiektu wyliczenia może zawierać wiele elementów członkowskich wyliczenia, a każdy element członkowski reprezentuje pole bitowe w wartości wyliczenia. Atrybut FlagsAttribute może służyć do wskazania, że wyliczenie składa się z pól bitowych. Na przykład wyliczenie o nazwie Pets może służyć do wskazywania rodzajów zwierząt domowych w gospodarstwie domowym. Można go zdefiniować w następujący sposób.

[Flags]
public enum Pets
{
    None = 0, Dog = 1, Cat = 2, Bird = 4, Rodent = 8,
    Reptile = 16, Other = 32
};
[<Flags>] 
type Pets =
    | None = 0
    | Dog = 1
    | Cat = 2
    | Bird = 4
    | Rodent = 8
    | Reptile = 16
    | Other = 32
<Flags> Public Enum Pets As Integer
   None = 0
   Dog = 1
   Cat = 2
   Bird = 4
   Rodent = 8
   Reptile = 16
   Other = 32
End Enum

Następnie Pets można użyć wyliczenia, jak pokazano w poniższym przykładzie.

Pets familyPets = Pets.Dog | Pets.Cat;
Console.WriteLine("Pets: {0:G} ({0:D})", familyPets);
// The example displays the following output:
//       Pets: Dog, Cat (3)
let familyPets = Pets.Dog ||| Pets.Cat
printfn $"Pets: {familyPets:G} ({familyPets:D})"
// The example displays the following output:
//       Pets: Dog, Cat (3)
Dim familyPets As Pets = Pets.Dog Or Pets.Cat
Console.WriteLine("Pets: {0:G} ({0:D})", familyPets)
' The example displays the following output:
'       Pets: Dog, Cat (3)

Podczas definiowania wyliczenia bitowego i stosowania atrybutu FlagsAttribute należy użyć następujących najlepszych rozwiązań.

  • Użyj atrybutu niestandardowego FlagsAttribute dla wyliczenia tylko wtedy, gdy operacja bitowa (AND, OR, EXCLUSIVE OR) ma być wykonywana na wartości liczbowej.

  • Zdefiniuj stałe wyliczenia w uprawnieniach dwóch, czyli 1, 2, 4, 8 itd. Oznacza to, że poszczególne flagi w połączonych stałych wyliczenia nie nakładają się na siebie.

  • Rozważ utworzenie stałej wyliczonej dla powszechnie używanych kombinacji flag. Jeśli na przykład masz wyliczenie używane dla operacji we/wy plików, które zawierają wyliczone stałe Read = 1 i Write = 2, rozważ utworzenie wyliczonej stałej ReadWrite = Read OR Write, która łączy Read flagi i Write . Ponadto bitowa operacja OR używana do łączenia flag może być uznawana za zaawansowaną koncepcję w pewnych okolicznościach, które nie powinny być wymagane w przypadku prostych zadań.

  • Zachowaj ostrożność, jeśli zdefiniujesz liczbę ujemną jako stałą wyliczeniową flagę, ponieważ wiele pozycji flag może być ustawionych na 1, co może spowodować, że kod będzie mylący i zachęca do błędów kodowania.

  • Wygodnym sposobem sprawdzenia, czy flaga jest ustawiona w wartości liczbowej, jest wywołanie metody wystąpienia HasFlag , jak pokazano w poniższym przykładzie.

    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.
    
    let familyPets = Pets.Dog ||| Pets.Cat
    if familyPets.HasFlag Pets.Dog then
        printfn "The family has a dog."
    // The example displays the following output:
    //       The family has a dog.
    
    Dim familyPets As Pets = Pets.Dog Or Pets.Cat
    If familyPets.HasFlag(Pets.Dog) Then
        Console.WriteLine("The family has a dog.")
    End If
    ' The example displays the following output:
    '       The family has a dog.
    

    Jest to odpowiednik wykonywania bitowej operacji AND między wartością liczbową a wyliczeniową stałą flagą, która ustawia wszystkie bity w wartości liczbowej na zero, które nie odpowiadają flagi, a następnie testuje, czy wynik tej operacji jest równy stałej wyliczonej flagi. Przedstawiono to w poniższym przykładzie.

    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.
    
    let familyPets = Pets.Dog ||| Pets.Cat
    if (familyPets &&& Pets.Dog) = Pets.Dog then
        printfn "The family has a dog."
    // The example displays the following output:
    //       The family has a dog.
    
    Dim familyPets As Pets = Pets.Dog Or Pets.Cat
    If familyPets And Pets.Dog = Pets.Dog Then
        Console.WriteLine("The family has a dog.")
    End If
    ' The example displays the following output:
    '       The family has a dog.
    
  • Użyj None jako nazwy flagi wyliczonej stałej, której wartość to zero. Nie można użyć wyliczonej stałej None w bitowej operacji AND, aby przetestować flagę, ponieważ wynik jest zawsze zerowy. Można jednak wykonać logiczne, a nie bitowe porównanie wartości liczbowej i wyliczonej stałej None , aby określić, czy są ustawione jakiekolwiek bity w wartości liczbowej. Przedstawiono to w poniższym przykładzie.

    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.
    
    let familyPets = Pets.Dog ||| Pets.Cat
    if familyPets = Pets.None then
        printfn "The family has no pets."
    else
        printfn "The family has pets."
    // The example displays the following output:
    //       The family has pets.
    
    Dim familyPets As Pets = Pets.Dog Or Pets.Cat
    If familyPets = Pets.None Then
        Console.WriteLine("The family has no pets.")
    Else
        Console.WriteLine("The family has pets.")
    End If
    ' The example displays the following output:
    '       The family has pets.
    
  • Nie należy definiować wartości wyliczenia wyłącznie w celu zdublowania stanu samego wyliczenia. Na przykład nie należy definiować wyliczonej stałej, która jedynie oznacza koniec wyliczenia. Jeśli musisz określić ostatnią wartość wyliczenia, sprawdź jawnie, czy ta wartość jest jawna. Ponadto można wykonać sprawdzanie zakresu dla pierwszej i ostatniej wyliczonej stałej, jeśli wszystkie wartości w zakresie są prawidłowe.

Dodawanie metod wyliczania

Ponieważ typy wyliczenia są definiowane przez struktury języków, takie jak enum (C#) i Enum (Visual Basic), nie można zdefiniować metod niestandardowych dla typu wyliczenia innego niż te metody dziedziczone z Enum klasy. Można jednak użyć metod rozszerzeń, aby dodać funkcjonalność do określonego typu wyliczenia.

W poniższym przykładzie Grades wyliczenie reprezentuje możliwe oceny listów, które student może otrzymać w klasie. Metoda rozszerzenia o nazwie Passing jest dodawana do Grades typu, aby każde wystąpienie tego typu teraz "wie", czy reprezentuje klasę przekazującą, czy nie. Klasa Extensions zawiera również statyczną zmienną odczytu i zapisu, która definiuje minimalną klasę przekazywania. Wartość Passing zwracana metody rozszerzenia odzwierciedla bieżącą wartość tej zmiennej.

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.
open System
open System.Runtime.CompilerServices
// Define an enumeration to represent student grades.
type Grades =
    | F = 0
    | D = 1
    | C = 2
    | B = 3
    | A = 4

let mutable minPassing = Grades.D

// Define an extension method for the Grades enumeration.
[<Extension>]
type Extensions =
    [<Extension>]
    static member Passing(grade) = grade >= minPassing

let g1 = Grades.D
let g2 = Grades.F
printfn $"""{g1} {if g1.Passing() then "is" else "is not"} a passing grade."""
printfn $"""{g2} {if g2.Passing() then "is" else "is not"} a passing grade."""

minPassing <- Grades.C
printfn "\nRaising the bar!\n"
printfn $"""{g1} {if g1.Passing() then "is" else "is not"} a passing grade."""
printfn $"""{g2} {if g2.Passing() then "is" else "is not"} a passing grade."""
// 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.
Imports System.Runtime.CompilerServices

' Define an enumeration to represent student grades.
Public Enum Grades As Integer
   F = 0
   D = 1
   C = 2
   B = 3
   A = 4
End Enum   

' Define an extension method for the Grades enumeration.
Public Module Extensions
  Public minPassing As Grades = Grades.D
 
  <Extension>
  Public Function Passing(grade As Grades) As Boolean
     Return grade >= minPassing
  End Function
End Module

Public Module Example
  Public Sub Main()
      Dim g1 As Grades = Grades.D
      Dim g2 As Grades = Grades.F
      Console.WriteLine("{0} {1} a passing grade.", 
                        g1, If(g1.Passing(), "is", "is not"))
      Console.WriteLine("{0} {1} a passing grade.", 
                        g2, If(g2.Passing(), "is", "is not"))
      Console.WriteLine()
      
      Extensions.minPassing = Grades.C
      Console.WriteLine("Raising the bar!")
      Console.WriteLine()
      Console.WriteLine("{0} {1} a passing grade.", 
                        g1, If(g1.Passing(), "is", "is not"))
      Console.WriteLine("{0} {1} a passing grade.", 
                        g2, If(g2.Passing(), "is", "is not"))
  End Sub
End Module
' 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.

Przykłady

W poniższym przykładzie pokazano użycie wyliczenia do reprezentowania nazwanych wartości i innego wyliczenia reprezentującego nazwane pola bitowe.

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);
    }
}
open System

type Days =
    | Saturday = 0
    | Sunday = 1
    | Monday = 2
    | Tuesday = 3
    | Wednesday = 4
    | Thursday = 5
    | Friday = 6

type BoilingPoints =
    | Celsius = 100
    | Fahrenheit = 212

[<Flags>]
type Colors =
    | Red = 1
    | Green = 2
    | Blue = 4
    | Yellow = 8

let weekdays = typeof<Days>
let boiling = typeof<BoilingPoints>

printfn "The days of the week, and their corresponding values in the Days Enum are:"

for s in Enum.GetNames weekdays do
    printfn $"""{s,-11}= {Enum.Format(weekdays, Enum.Parse(weekdays, s), "d")}"""

printfn "\nEnums can also be created which have values that represent some meaningful amount."
printfn "The BoilingPoints Enum defines the following items, and corresponding values:"

for s in Enum.GetNames boiling do
    printfn $"""{s,-11}= {Enum.Format(boiling, Enum.Parse(boiling, s), "d")}"""

let myColors = Colors.Red ||| Colors.Blue ||| Colors.Yellow
printfn $"\nmyColors holds a combination of colors. Namely: {myColors}"
Public Class EnumTest
    Enum Days
        Saturday
        Sunday
        Monday
        Tuesday
        Wednesday
        Thursday
        Friday
    End Enum 
    
    Enum BoilingPoints
        Celsius = 100
        Fahrenheit = 212
    End Enum 
    
    <Flags()> _
    Enum Colors
        Red = 1
        Green = 2
        Blue = 4
        Yellow = 8
    End Enum 

    Public Shared Sub Main()
        Dim weekdays As Type = GetType(Days)
        Dim boiling As Type = GetType(BoilingPoints)

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

        Dim s As String
        For Each s In  [Enum].GetNames(weekdays)
            Console.WriteLine("{0,-11} = {1}", s, [Enum].Format(weekdays, [Enum].Parse(weekdays, s), "d"))
        
        Next s
        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:")

        For Each s In  [Enum].GetNames(boiling)
            Console.WriteLine("{0,-11} = {1}", s, [Enum].Format(boiling, [Enum].Parse(boiling, s), "d"))
        Next s

        Dim myColors As Colors = Colors.Red Or Colors.Blue Or Colors.Yellow
        Console.WriteLine()
        Console.WriteLine("myColors holds a combination of colors. Namely: {0}", myColors)
    End Sub 
End Class