Поиск…


Вступление

Перечисление может быть получено из любого из следующих типов: байт, sbyte, short, ushort, int, uint, long, ulong. Значение по умолчанию - int, и его можно изменить, указав тип в определении перечисления:

public enum Weekday: byte {Понедельник = 1, вторник = 2, среда = 3, четверг = 4, пятница = 5}

Это полезно, когда P / Invoking для собственного кода, сопоставление с источниками данных и аналогичные обстоятельства. В общем случае следует использовать значение по умолчанию int, поскольку большинство разработчиков ожидают, что enum будет int.

Синтаксис

  • enum Colors {Red, Green, Blue} // Объявление enum
  • enum Цвета: байт {Красный, Зеленый, Синий} // Декларация определенного типа
  • enum Colors {Red = 23, Green = 45, Blue = 12} // Объявление с заданными значениями
  • Colors.Red // Доступ к элементу Enum
  • int value = (int) Colors.Red // Получить значение int элемента перечисления
  • Цвета color = (Цвета) intValue // Получить элемент перечисления из int

замечания

Enum (сокращение от «перечисляемого типа») представляет собой тип, состоящий из набора именованных констант, представленного идентификатором типа.

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

Получить все значения элементов перечисления

enum MyEnum
{
    One,
    Two,
    Three
}

foreach(MyEnum e in Enum.GetValues(typeof(MyEnum)))
    Console.WriteLine(e);

Это напечатает:

One
Two
Three

Enum как флаги

FlagsAttribute может быть применен к перечислению, изменяющему поведение ToString() чтобы соответствовать характеру перечисления:

[Flags]
enum MyEnum
{
    //None = 0, can be used but not combined in bitwise operations
    FlagA = 1,
    FlagB = 2,
    FlagC = 4,
    FlagD = 8  
    //you must use powers of two or combinations of powers of two 
    //for bitwise operations to work
}

var twoFlags = MyEnum.FlagA | MyEnum.FlagB;

// This will enumerate all the flags in the variable: "FlagA, FlagB".
Console.WriteLine(twoFlags);

Поскольку FlagsAttribute полагается на константы перечисления как полномочия двух (или их комбинаций), а значения перечисления в конечном счете являются числовыми значениями, вы ограничены размером базового числового типа. Самый большой доступный числовой тип, который вы можете использовать, - UInt64 , который позволяет указать 64 различных (не комбинированных) константы перечисления флага. Ключевое слово enum умолчанию относится к базовому типу int , который является Int32 . Компилятор позволит объявить значения шириной более 32 бит. Они обернутся без предупреждения и приведут к тому, что два или более члена перечисления будут иметь одинаковое значение. Поэтому, если перечисление предназначено для размещения битового набора из более чем 32 флагов, вам необходимо указать более крупный тип:

public enum BigEnum : ulong
{
    BigValue = 1 << 63
}

Хотя флаги часто имеют только один бит, их можно объединить в названные «наборы» для более легкого использования.

[Flags]
enum FlagsEnum
{
    None = 0,
    Option1 = 1,
    Option2 = 2,
    Option3 = 4,
       
    Default = Option1 | Option3,
    All = Option1 | Option2 | Option3,
}

Чтобы не указывать десятичные значения степеней двух, оператор сдвига слева (<<) также может быть использован для объявления того же перечисления

[Flags]
enum FlagsEnum
{
    None = 0,
    Option1 = 1 << 0,
    Option2 = 1 << 1,
    Option3 = 1 << 2,
       
    Default = Option1 | Option3,
    All = Option1 | Option2 | Option3,
}

Начиная с C # 7.0, бинарные литералы также могут использоваться.

Чтобы проверить, имеет ли значение переменной enum определенный флаг, может использоваться метод HasFlag . Допустим, у нас есть

[Flags]
enum MyEnum
{
    One = 1,
    Two = 2,
    Three = 4
}

И value

var value = MyEnum.One | MyEnum.Two;

С HasFlag мы можем проверить, установлен ли какой-либо из флагов

if(value.HasFlag(MyEnum.One))
    Console.WriteLine("Enum has One");

if(value.HasFlag(MyEnum.Two))
    Console.WriteLine("Enum has Two");

if(value.HasFlag(MyEnum.Three))
    Console.WriteLine("Enum has Three");

Также мы можем перебирать все значения enum, чтобы получить все установленные флаги

var type = typeof(MyEnum);
var names = Enum.GetNames(type);

foreach (var name in names)
{
    var item = (MyEnum)Enum.Parse(type, name);

    if (value.HasFlag(item))
        Console.WriteLine("Enum has " + name);
}

Или же

foreach(MyEnum flagToCheck in Enum.GetValues(typeof(MyEnum)))
{
    if(value.HasFlag(flagToCheck))
    {
         Console.WriteLine("Enum has " + flagToCheck);
    }
}

Все три примера будут напечатаны:

Enum has One
Enum has Two

Тестирование флажков в стиле enum с побитовой логикой

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

[Flags]
enum FlagsEnum
{
    Option1 = 1,
    Option2 = 2,
    Option3 = 4,
    Option2And3 = Option2 | Option3;

    Default = Option1 | Option3,
}

Значение по Default представляет собой комбинацию двух других, объединенных с побитовым ИЛИ. Поэтому для проверки наличия флага нам нужно использовать побитовое И.

var value = FlagsEnum.Default;

bool isOption2And3Set = (value & FlagsEnum.Option2And3) == FlagsEnum.Option2And3;

Assert.True(isOption2And3Set);

Перечисление в строку и обратно

public enum DayOfWeek
{
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday
}

    
// Enum to string
string thursday = DayOfWeek.Thursday.ToString(); // "Thursday"

string seventhDay = Enum.GetName(typeof(DayOfWeek), 6); // "Saturday"

string monday = Enum.GetName(typeof(DayOfWeek), DayOfWeek.Monday); // "Monday"


// String to enum (.NET 4.0+ only - see below for alternative syntax for earlier .NET versions)
DayOfWeek tuesday;
Enum.TryParse("Tuesday", out tuesday); // DayOfWeek.Tuesday

DayOfWeek sunday;
bool matchFound1 = Enum.TryParse("SUNDAY", out sunday); // Returns false (case-sensitive match)

DayOfWeek wednesday;
bool matchFound2 = Enum.TryParse("WEDNESDAY", true, out wednesday); // Returns true; DayOfWeek.Wednesday (case-insensitive match)


// String to enum (all .NET versions)
DayOfWeek friday = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), "Friday"); // DayOfWeek.Friday

DayOfWeek caturday = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), "Caturady"); // Thows ArgumentException

// All names of an enum type as strings
string[] weekdays = Enum.GetNames(typeof(DayOfWeek));

Значение по умолчанию для перечисления == ZERO

Значение по умолчанию для перечисления равно нулю . Если перечисление не определяет элемент со значением нуля, его значение по умолчанию будет равно нулю.

public class Program
{        
    enum EnumExample
    {
        one = 1,
        two = 2
    }
    
    public void Main()
    {              
        var e = default(EnumExample);
        
        if (e == EnumExample.one)
            Console.WriteLine("defaults to one");
        else
            Console.WriteLine("Unknown");    
    }    
}

Пример: https://dotnetfiddle.net/l5Rwie

Основы Enum

Из MSDN :

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

По сути, перечисление - это тип, который допускает только набор конечных опций, и каждый параметр соответствует числу. По умолчанию эти числа увеличиваются в том порядке, в котором объявлены значения, начиная с нуля. Например, можно объявить перечисление для дней недели:

public enum Day
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

Это перечисление можно использовать следующим образом:

// Define variables with values corresponding to specific days
Day myFavoriteDay = Day.Friday;
Day myLeastFavoriteDay = Day.Monday;

// Get the int that corresponds to myFavoriteDay
// Friday is number 4
int myFavoriteDayIndex = (int)myFavoriteDay;

// Get the day that represents number 5
Day dayFive = (Day)5;

По умолчанию базовым типом каждого элемента в enum является int , но также могут использоваться byte , sbyte , short , ushort , uint , long и ulong . Если вы используете тип, отличный от int , вы должны указать тип, используя двоеточие после имени перечисления:

public enum Day : byte 
{
    // same as before 
}

Числа после имени теперь являются байтами вместо целых чисел. Вы можете получить базовый тип перечисления следующим образом:

Enum.GetUnderlyingType(typeof(Days)));

Выход:

System.Byte

Демо: .NET скрипка

Побитовая манипуляция с использованием перечислений

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

Пример 1: С помощью [Флаги]

[Flags]
enum Colors
{
    Red=1,
    Blue=2,
    Green=4,
    Yellow=8
}

var color = Colors.Red | Colors.Blue;
Console.WriteLine(color.ToString());

печатает красный, синий

Пример 2: Без [Флаги]

enum Colors
{
    Red=1,
    Blue=2,
    Green=4,
    Yellow=8
}
var color = Colors.Red | Colors.Blue;
Console.WriteLine(color.ToString());

отпечатки 3

Использование << обозначение для флагов

Оператор левого сдвига ( << ) может использоваться в объявлениях перечисления флагов, чтобы гарантировать, что каждый флаг имеет ровно один 1 в двоичном представлении, как и должны быть флаги.

Это также помогает улучшить читаемость больших перечислений с большим количеством флагов в них.

[Flags]
public enum MyEnum 
{
    None  = 0,
    Flag1 = 1 << 0,
    Flag2 = 1 << 1,
    Flag3 = 1 << 2,
    Flag4 = 1 << 3,
    Flag5 = 1 << 4,
    ...
    Flag31 = 1 << 30
}

Теперь очевидно, что MyEnum содержит только соответствующие флаги, а не какие-то грязные вещи, такие как Flag30 = 1073741822 (или 11111111111111111111111111111110 в двоичном формате), что неуместно.

Добавление дополнительной информации описания к значению перечисления

В некоторых случаях вам может потребоваться добавить дополнительное описание к значению перечисления, например, когда значение enum становится менее читаемым, чем то, что вы можете отобразить пользователю. В таких случаях вы можете использовать класс System.ComponentModel.DescriptionAttribute .

Например:

public enum PossibleResults
{
    [Description("Success")]
    OK = 1,
    [Description("File not found")]
    FileNotFound = 2,
    [Description("Access denied")]
    AccessDenied = 3
}

Теперь, если вы хотите вернуть описание определенного значения перечисления, вы можете сделать следующее:

public static string GetDescriptionAttribute(PossibleResults result)
{
        return ((DescriptionAttribute)Attribute.GetCustomAttribute((result.GetType().GetField(result.ToString())), typeof(DescriptionAttribute))).Description;
}

static void Main(string[] args)
{
    PossibleResults result = PossibleResults.FileNotFound;
    Console.WriteLine(result); // Prints "FileNotFound"
    Console.WriteLine(GetDescriptionAttribute(result)); // Prints "File not found"
}

Это также может быть легко преобразовано в метод расширения для всех перечислений:

static class EnumExtensions
{
    public static string GetDescription(this Enum enumValue)
    {
        return ((DescriptionAttribute)Attribute.GetCustomAttribute((enumValue.GetType().GetField(enumValue.ToString())), typeof(DescriptionAttribute))).Description;
    }
}

И тогда легко использовать так: Console.WriteLine(result.GetDescription());

Добавление и удаление значений из помеченного значком перечисления

Этот код предназначен для добавления и удаления значения из помеченного enum-экземпляра:

[Flags]
public enum MyEnum
{
    Flag1 = 1 << 0,
    Flag2 = 1 << 1,
    Flag3 = 1 << 2
}

var value = MyEnum.Flag1;

// set additional value
value |= MyEnum.Flag2;  //value is now Flag1, Flag2
value |= MyEnum.Flag3;  //value is now Flag1, Flag2, Flag3

// remove flag
value &= ~MyEnum.Flag2; //value is now Flag1, Flag3    

Перечисления могут иметь неожиданные значения

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

Хотя приведенный ниже тип перечисления DaysOfWeek имеет только 7 определенных значений, он все равно может содержать любое значение int .

public enum DaysOfWeek
{
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 4,
    Friday = 5,
    Saturday = 6,
    Sunday = 7
}

DaysOfWeek d = (DaysOfWeek)31;
Console.WriteLine(d); // prints 31

DaysOFWeek s = DaysOfWeek.Sunday;
s++; // No error

В настоящее время нет способа определить перечисление, которое не имеет такого поведения.

Однако неопределенные значения перечисления могут быть обнаружены с помощью метода Enum.IsDefined . Например,

DaysOfWeek d = (DaysOfWeek)31;
Console.WriteLine(Enum.IsDefined(typeof(DaysOfWeek),d)); // prints False


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow