Поделиться через


Типы перечисления (справочник по C#)

Тип перечисления (или тип перечисления) — это тип значения, определенный набором именованных констант базового целочисленного числового типа. Чтобы определить тип перечисления, используйте ключевое enum слово и укажите имена элементов перечисления:

enum Season
{
    Spring,
    Summer,
    Autumn,
    Winter
}

По умолчанию связанные константные значения членов перечисления имеют тип int; они начинаются с нуля и увеличиваются на один в порядке следования в тексте определения. Можно явно указать любой другой целочисленный числовой тип в качестве базового типа перечисления. Можно также явно указать связанные значения констант, как показано в следующем примере:

enum ErrorCode : ushort
{
    None = 0,
    Unknown = 1,
    ConnectionLost = 100,
    OutlierReading = 200
}

Невозможно определить метод внутри определения типа перечисления. Чтобы добавить функцию в тип перечисления, создайте член расширения.

Значение по умолчанию для типа перечисления E — это значение, определяемое выражением (E)0, даже если ноль не соответствует ни одному из членов перечисления.

Неявные преобразования из нуля

C# позволяет неявным преобразованиям из литерального значения 0 в любой тип перечисления и от const значений, равных нулю. Это поведение может привести к непредвиденным результатам, если перечисление не содержит член с нулевым значением:

public enum GpioPort
{
    GpioA = 1,
    GpioB,
    GpioC,
    GpioD
}

public class ZeroConversionExample
{
    public static void Main()
    {
        // This compiles without warning but creates an invalid enum value
        GpioPort port1 = (GpioPort)0;
        Console.WriteLine($"port1: {port1}"); // Output: port1: 0

        // This also compiles due to implicit conversion from zero
        GpioPort port2 = GetPort(0);
        Console.WriteLine($"port2: {port2}"); // Output: port2: 0

        // Check if the enum value is valid
        bool isValid1 = Enum.IsDefined(typeof(GpioPort), port1);
        bool isValid2 = Enum.IsDefined(typeof(GpioPort), port2);
        Console.WriteLine($"port1 is valid: {isValid1}"); // Output: port1 is valid: False
        Console.WriteLine($"port2 is valid: {isValid2}"); // Output: port2 is valid: False

        // Safer approach - validate enum values
        if (Enum.IsDefined(typeof(GpioPort), 0))
        {
            GpioPort safePort = (GpioPort)0;
        }
        else
        {
            Console.WriteLine("Value 0 is not a valid GpioPort");
            // Handle the invalid case appropriately
        }
    }

    public static GpioPort GetPort(GpioPort port)
    {
        return port;
    }
}

В предыдущем примере port1 оба и port2 назначены значение 0, но GpioPort не имеет элемента с этим значением. Метод Enum.IsDefined подтверждает, что эти значения являются недопустимыми значениями перечисления.

Это неявное преобразование существует, так как 0-разрядный шаблон является стандартным для всех типов структур, включая все типы перечисления. Однако она может привести к ошибкам в коде. Чтобы избежать этих проблем:

  • Вы должны почти всегда определять член со значением 0 в перечислениях.
  • Используется Enum.IsDefined для проверки значений перечисления при преобразовании из числовых типов.
  • При использовании числовых параметров, которые могут быть неявно преобразованы в типы перечисления.

Тип перечисления используется для представления выбора из набора взаимоисключающих значений или сочетания вариантов. Чтобы представить сочетание вариантов, определите тип перечисления как битовые флаги.

Типы перечисления в виде битовых флагов

Если вы хотите, чтобы тип перечисления представлял собой комбинацию вариантов, определите элементы перечисления для этих вариантов так, чтобы каждый отдельный выбор был битовым полем. То есть связанные значения этих членов перечисления должны быть степенями двойки. Затем можно использовать побитовые логические операторы | или & объединять варианты или пересекать сочетания вариантов соответственно. Чтобы указать, что тип перечисления объявляет битовые поля, примените к нему атрибут Flags . Как показано в следующем примере, можно также включить некоторые типичные сочетания в определение типа перечисления.

[Flags]
public enum Days
{
    None      = 0b_0000_0000,  // 0
    Monday    = 0b_0000_0001,  // 1
    Tuesday   = 0b_0000_0010,  // 2
    Wednesday = 0b_0000_0100,  // 4
    Thursday  = 0b_0000_1000,  // 8
    Friday    = 0b_0001_0000,  // 16
    Saturday  = 0b_0010_0000,  // 32
    Sunday    = 0b_0100_0000,  // 64
    Weekend   = Saturday | Sunday
}

public class FlagsEnumExample
{
    public static void Main()
    {
        Days meetingDays = Days.Monday | Days.Wednesday | Days.Friday;
        Console.WriteLine(meetingDays);
        // Output:
        // Monday, Wednesday, Friday

        Days workingFromHomeDays = Days.Thursday | Days.Friday;
        Console.WriteLine($"Join a meeting by phone on {meetingDays & workingFromHomeDays}");
        // Output:
        // Join a meeting by phone on Friday

        bool isMeetingOnTuesday = (meetingDays & Days.Tuesday) == Days.Tuesday;
        Console.WriteLine($"Is there a meeting on Tuesday: {isMeetingOnTuesday}");
        // Output:
        // Is there a meeting on Tuesday: False

        var a = (Days)37;
        Console.WriteLine(a);
        // Output:
        // Monday, Wednesday, Saturday
    }
}

Дополнительные сведения и примеры см. на System.FlagsAttribute странице справочника по API и в разделе Неисключаемые члены и атрибут Flags на странице справочника System.Enum API.

Тип System.Enum и ограничение перечисления

Тип System.Enum является абстрактным базовым классом всех типов перечисления. Он предоставляет ряд методов для получения сведений о типе перечисления и его значениях. Дополнительные сведения и примеры см. на странице справочника System.Enum по API.

Можно использовать System.Enum в ограничении базового класса (которое называется ограничением перечисления), чтобы указать, что параметр типа является типом перечисления. Любой тип перечисления также удовлетворяет struct ограничению, которое используется для указания того, что параметр типа является типом ненулевого значения.

Преобразования

Для любого типа перечисления существуют явные преобразования между типом перечисления и его базовым целочисленным типом. Если вы приведете значение перечисления к его базовому типу, результатом является связанное целочисленное значение элемента перечисления.

public enum Season
{
    Spring,
    Summer,
    Autumn,
    Winter
}

public class EnumConversionExample
{
    public static void Main()
    {
        Season a = Season.Autumn;
        Console.WriteLine($"Integral value of {a} is {(int)a}");  // output: Integral value of Autumn is 2

        var b = (Season)1;
        Console.WriteLine(b);  // output: Summer

        var c = (Season)4;
        Console.WriteLine(c);  // output: 4
    }
}

Enum.IsDefined Используйте метод, чтобы определить, содержит ли тип перечисления элемент перечисления с определенным связанным значением.

Для любого типа перечисления существуют преобразования упаковки и распаковки в System.Enum тип и из него соответственно.

Спецификация языка C#

Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:

См. также