Как мне перечислить перечисление в C #?

3329

Как вы можете перечислить enum в С#?

например. следующий код не компилируется:

public enum Suit 
{
    Spades,
    Hearts,
    Clubs,
    Diamonds
}

public void EnumerateAllSuitsDemoMethod() 
{
    foreach (Suit suit in Suit) 
    {
        DoSomething(suit);
    }
}

И дает следующую ошибку времени компиляции:

"Костюм" - это "тип", но используется как "переменная"

Не выполняется ключевое слово Suit, второе.

  • 11
    Смотрите также ... stackoverflow.com/questions/972307/…
  • 1
    Вы можете проверить все входы и выходы перечислений C # , которые обсуждают это, а также другие полезные трюки enum
Показать ещё 1 комментарий
Теги:
enums
enumeration

26 ответов

4322
Лучший ответ
foreach (Suit suit in (Suit[]) Enum.GetValues(typeof(Suit)))
{
}

Примечание: приведение к (Suit[]) не является строго необходимым, но делает код быстрее на 0,5 нс.

  • 83
    Это не работает, если у вас есть повторяющиеся значения в списке перечислителя.
  • 2
    @Jessy, если вам нужны все имена (включая имена с повторяющимися значениями), возможно, попробуйте Enum.GetNames вместе с Enum.Parse. Это будет немного медленно, но я рекомендую сделать это один раз во время инициализации (или в первый раз, когда это необходимо) и кэшировать результаты в массив.
Показать ещё 9 комментариев
576

Мне кажется, что вы действительно хотите распечатать имена каждого перечисления, а не значения. В этом случае Enum.GetNames() представляется правильным подходом.

public enum Suits
{
    Spades,
    Hearts,
    Clubs,
    Diamonds,
    NumSuits
}

public void PrintAllSuits()
{
    foreach (string name in Enum.GetNames(typeof(Suits)))
    {
        System.Console.WriteLine(name);
    }
}

Кстати, приращение значения не является хорошим способом перечислить значения перечисления. Вы должны сделать это вместо этого.

Вместо этого я использовал бы Enum.GetValues(typeof(Suit)).

public enum Suits
{
    Spades,
    Hearts,
    Clubs,
    Diamonds,
    NumSuits
}

public void PrintAllSuits()
{
    foreach (var suit in Enum.GetValues(typeof(Suits)))
    {
        System.Console.WriteLine(suit.ToString());
    }
}
  • 0
    Синтаксис VB здесь: ссылка
300

Я сделал несколько расширений для простого использования перечисления, возможно, кто-то может его использовать...

public static class EnumExtensions
{
    /// <summary>
    /// Gets all items for an enum value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    public static IEnumerable<T> GetAllItems<T>(this Enum value)
    {
        foreach (object item in Enum.GetValues(typeof(T)))
        {
            yield return (T)item;
        }
    }

    /// <summary>
    /// Gets all items for an enum type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    public static IEnumerable<T> GetAllItems<T>() where T : struct
    {
        foreach (object item in Enum.GetValues(typeof(T)))
        {
            yield return (T)item;
        }
    }

    /// <summary>
    /// Gets all combined items from an enum value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    /// <example>
    /// Displays ValueA and ValueB.
    /// <code>
    /// EnumExample dummy = EnumExample.Combi;
    /// foreach (var item in dummy.GetAllSelectedItems<EnumExample>())
    /// {
    ///    Console.WriteLine(item);
    /// }
    /// </code>
    /// </example>
    public static IEnumerable<T> GetAllSelectedItems<T>(this Enum value)
    {
        int valueAsInt = Convert.ToInt32(value, CultureInfo.InvariantCulture);

        foreach (object item in Enum.GetValues(typeof(T)))
        {
            int itemAsInt = Convert.ToInt32(item, CultureInfo.InvariantCulture);

            if (itemAsInt == (valueAsInt & itemAsInt))
            {
                yield return (T)item;
            }
        }
    }

    /// <summary>
    /// Determines whether the enum value contains a specific value.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <param name="request">The request.</param>
    /// <returns>
    ///     <c>true</c> if value contains the specified value; otherwise, <c>false</c>.
    /// </returns>
    /// <example>
    /// <code>
    /// EnumExample dummy = EnumExample.Combi;
    /// if (dummy.Contains<EnumExample>(EnumExample.ValueA))
    /// {
    ///     Console.WriteLine("dummy contains EnumExample.ValueA");
    /// }
    /// </code>
    /// </example>
    public static bool Contains<T>(this Enum value, T request)
    {
        int valueAsInt = Convert.ToInt32(value, CultureInfo.InvariantCulture);
        int requestAsInt = Convert.ToInt32(request, CultureInfo.InvariantCulture);

        if (requestAsInt == (valueAsInt & requestAsInt))
        {
            return true;
        }

        return false;
    }
}

Само перечисление должно быть украшено FlagsAttribute

[Flags]
public enum EnumExample
{
    ValueA = 1,
    ValueB = 2,
    ValueC = 4,
    ValueD = 8,
    Combi = ValueA | ValueB
}
  • 12
    Один вкладыш для первого метода расширения; это больше не ленивый. вернуть Enum.GetValues (typeof (T)). Cast <T> ();
  • 2
    В качестве альтернативы вы также можете использовать OfType: Enum.GetValues (typeof (T)). OfType <T> (). Жаль, что нет универсальной версии GetValues <T> (), тогда она была бы еще более привлекательной.
Показать ещё 8 комментариев
149

Некоторые версии платформы .NET не поддерживают Enum.GetValues. Здесь хорошее обходное решение от Идеи 2.0: Enum.GetValues ​​в Compact Framework:

public List<Enum> GetValues(Enum enumeration)
{
   List<Enum> enumerations = new List<Enum>();
   foreach (FieldInfo fieldInfo in enumeration.GetType().GetFields(
         BindingFlags.Static | BindingFlags.Public))
   {
      enumerations.Add((Enum)fieldInfo.GetValue(enumeration));
   }
   return enumerations;
}

Как и любой код, который включает reflection, вы должны предпринять шаги, чтобы гарантировать, что он запускается только один раз, и результаты кэшируются.

  • 17
    Почему бы не использовать здесь ключевое слово yield вместо создания списка?
  • 1
    или короче: return type.GetFields().Where(x => x.IsLiteral).Select(x => x.GetValue(null)).Cast<Enum>();
Показать ещё 2 комментария
86

Я думаю, что это более эффективно, чем другие предложения, потому что GetValues() не вызывается каждый раз, когда у вас есть цикл. Это также более красноречиво. И вы получаете ошибку времени компиляции, а не исключение во время выполнения, если Suit не является enum.

EnumLoop<Suit>.ForEach((suit) => {
    DoSomethingWith(suit);
});

EnumLoop имеет это полностью общее определение:

class EnumLoop<Key> where Key : struct, IConvertible {
    static readonly Key[] arr = (Key[])Enum.GetValues(typeof(Key));
    static internal void ForEach(Action<Key> act) {
        for (int i = 0; i < arr.Length; i++) {
            act(arr[i]);
        }
    }
}
  • 6
    Осторожнее с использованием таких дженериков. Если вы попытаетесь использовать EnumLoop с каким-либо типом, который не является enum, он скомпилируется нормально, но выдает исключение во время выполнения.
  • 6
    Спасибо, Свик. Исключения во время выполнения будут на самом деле возникать с другими ответами на этой странице ... кроме этого, потому что я добавил "где ключ: структура, IConvertible", чтобы вы получили ошибку времени компиляции в большинстве случаев.
Показать ещё 5 комментариев
85

Почему никто не использует Cast<T>?

var suits = Enum.GetValues(typeof(Suit)).Cast<Suit>();

Там вы идете IEnumerable<Suit>.

  • 1
    Это очень круто, если вы можете использовать LINQ ...
  • 0
    Это также работает в предложении from и в foreach заголовка foreach .
71

Вы не получите Enum.GetValues() в Silverlight.

Отправка оригинального сообщения от Einar Ingebrigtsen:

public class EnumHelper
{
    public static T[] GetValues<T>()
    {
        Type enumType = typeof(T);

        if (!enumType.IsEnum)
        {
            throw new ArgumentException("Type '" + enumType.Name + "' is not an enum");
        }

        List<T> values = new List<T>();

        var fields = from field in enumType.GetFields()
                     where field.IsLiteral
                     select field;

        foreach (FieldInfo field in fields)
        {
            object value = field.GetValue(enumType);
            values.Add((T)value);
        }

        return values.ToArray();
    }

    public static object[] GetValues(Type enumType)
    {
        if (!enumType.IsEnum)
        {
            throw new ArgumentException("Type '" + enumType.Name + "' is not an enum");
        }

        List<object> values = new List<object>();

        var fields = from field in enumType.GetFields()
                     where field.IsLiteral
                     select field;

        foreach (FieldInfo field in fields)
        {
            object value = field.GetValue(enumType);
            values.Add(value);
        }

        return values.ToArray();
    }
}
  • 2
    Хорошее решение, но рефакторинг будет лучше! :)
  • 0
    Я использую .NET Framework 4.0 и Silverlight enum.getvalues работают, код, который я использовал --- --- enum.GetValues (typeof (enum))
Показать ещё 1 комментарий
55

Просто добавьте мое решение, которое работает в компактной структуре (3.5) и поддерживает проверку типов во время компиляции:

public static List<T> GetEnumValues<T>() where T : new() {
    T valueType = new T();
    return typeof(T).GetFields()
        .Select(fieldInfo => (T)fieldInfo.GetValue(valueType))
        .Distinct()
        .ToList();
}

public static List<String> GetEnumNames<T>() {
    return typeof (T).GetFields()
        .Select(info => info.Name)
        .Distinct()
        .ToList();
}

- Если кто-то знает, как избавиться от T valueType = new T(), я был бы рад увидеть решение.

Вызов будет выглядеть так:

List<MyEnum> result = Utils.GetEnumValues<MyEnum>();
  • 2
    как насчет использования T valueType = default(T) ?
  • 0
    Отлично, я даже не знал это ключевое слово. Всегда приятно узнавать что-то новое. Спасибо! Всегда ли он возвращает ссылку на один и тот же объект или создает новый экземпляр каждый раз, когда вызывается оператор по умолчанию? До сих пор я не нашел в сети ничего об этом, но если он каждый раз создает новый экземпляр, это как бы побеждает цель, которую я искал (наличие однострочника ^^).
Показать ещё 7 комментариев
48

Я думаю, вы можете использовать

Enum.GetNames(Suit)
  • 6
    Enum.GetValues (костюмы)
44
public void PrintAllSuits()
{
    foreach(string suit in Enum.GetNames(typeof(Suits)))
    {
        Console.WriteLine(suit);
    }
}
  • 2
    Это перечисляет строку, не забудьте преобразовать эти вещи обратно в значение перечисления, чтобы перечисление могло быть перечислено.
  • 0
    Из ваших правок я вижу, что вы действительно хотите работать с самими перечислениями, приведенный выше код адресован вашему исходному сообщению.
43
foreach (Suit suit in Enum.GetValues(typeof(Suit))) { }

Я слышал смутные слухи, что это существенно медленнее. Кто-нибудь знает? - Орион Edwards 15 окт 2008 в 1:31 7

Я думаю, что кеширование массива значительно ускорит его. Похоже, вы каждый раз получаете новый массив (через отражение). Скорее всего:

Array enums = Enum.GetValues(typeof(Suit));
foreach (Suit suitEnum in enums) 
{
    DoSomething(suitEnum);
}

Это, по крайней мере, немного быстрее, ja?

  • 4
    Об этом должен позаботиться компилятор.
  • 0
    @StephanBijzitter Ого, вы читаете довольно далеко об этом :-) Я согласен, компилятор должен сделать мое решение ненужным.
Показать ещё 2 комментария
24

Три способа:

1. Enum.GetValues(type) //since .NET 1.1, not in silverlight or compact framewok
2. type.GetEnumValues() //only on .NET 4 and above
3. type.GetFields().Where(x => x.IsLiteral).Select(x => x.GetValue(null)) //works everywhere

Не знаю, почему было введено GetEnumValues в экземпляре типа, оно для меня совсем не читаемо.


Наличие вспомогательного класса, такого как Enum<T>, является наиболее читаемым и запоминающимся для меня:

public static class Enum<T> where T : struct, IComparable, IFormattable, IConvertible
{
    public static IEnumerable<T> GetValues()
    {
        return (T[])Enum.GetValues(typeof(T));
    }

    public static IEnumerable<string> GetNames()
    {
        return Enum.GetNames(typeof(T));
    }
}

Теперь вы вызываете:

Enum<Suit>.GetValues();
//or
Enum.GetValues(typeof(Suit)); //pretty consistent style

Можно также использовать кеширование, если производительность имеет значение, но я не ожидаю, что это будет проблемой вообще

public static class Enum<T> where T : struct, IComparable, IFormattable, IConvertible
{
    //lazily loaded
    static T[] values;
    static string[] names;

    public static IEnumerable<T> GetValues()
    {
        return values ?? (values = (T[])Enum.GetValues(typeof(T)));
    }

    public static IEnumerable<string> GetNames()
    {
        return names ?? (names = Enum.GetNames(typeof(T)));
    }
}
  • 0
    Это хорошее резюме методов. Я думаю, что вы должны объединить свой другой ответ в этом, хотя. Правда в том, что перечисления являются особыми, и их циклирование часто (обычно) так же верно, как перечисление, потому что вы знаете, что значения никогда не изменятся. Итак, если у вас есть enum, который постоянно меняется, то вы выбрали для начала неправильную конструкцию данных.
22

Существует два способа итерации Enum:

1. var values =  Enum.GetValues(typeof(myenum))
2. var values =  Enum.GetNames(typeof(myenum))

Первый даст вам значения в форме массива object, а второй даст вам значения в виде массива String.

Используйте его в цикле foreach, как показано ниже:

foreach(var value in values)
{
    //Do operations here
}
  • 2
    Кто не голосует .... это работает отлично ... и хотя бы добавить комментарий, что они считают неправильным?
  • 5
    подавление голосов даже без объяснения причин действительно несправедливо
Показать ещё 2 комментария
22

Что, черт возьми, я брошу свои два пенсов, просто объединив верхние ответы, которые я объединил, очень простое расширение

public static class EnumExtensions
{
    /// <summary>
    /// Gets all items for an enum value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    public static IEnumerable<T> GetAllItems<T>(this Enum value)
    {
        return (T[])Enum.GetValues(typeof (T));
    }
}

Очистите простые и быстрым комментарием @Jeppe-Stig-Nielsen.

  • 2
    Начиная с C # 7.3 (Visual Studio 2017 ≥ v15.7), можно использовать where T: Enum
20

Я использую ToString(), затем разделяю и разбираю массив вершин в флагах.

[Flags]
public enum ABC {
   a = 1,
   b = 2,
   c = 4
};

public IEnumerable<ABC> Getselected (ABC flags)
{
   var values = flags.ToString().Split(',');
   var enums = values.Select(x => (ABC)Enum.Parse(typeof(ABC), x.Trim()));
   return enums;
}

ABC temp= ABC.a | ABC.b;
var list = getSelected (temp);
foreach (var item in list)
{
   Console.WriteLine(item.ToString() + " ID=" + (int)item);
}
15

Если вам нужна проверка скорости и типа при сборке и времени выполнения, этот вспомогательный метод лучше, чем использование LINQ для создания каждого элемента:

public static T[] GetEnumValues<T>() where T : struct, IComparable, IFormattable, IConvertible
{
    if (typeof(T).BaseType != typeof(Enum))
    {
        throw new ArgumentException(string.Format("{0} is not of type System.Enum", typeof(T)));
    }
    return Enum.GetValues(typeof(T)) as T[];
}

И вы можете использовать его, как показано ниже:

static readonly YourEnum[] _values = GetEnumValues<YourEnum>();

Конечно, вы можете вернуть IEnumerable<T>, но вы ничего здесь не покупаете.

  • 1
    Начиная с C # 7.3 (Visual Studio 2017 ≥ v15.7), можно использовать where T: Enum
15

Я не считаю, что это лучше или даже хорошо, просто заявив еще одно решение.

Если значения перечислимого диапазона строго от 0 до n - 1, то общая альтернатива:

public void EnumerateEnum<T>()
{
    int length = Enum.GetValues(typeof(T)).Length;
    for (var i = 0; i < length; i++)
    {
        var @enum = (T)(object)i;
    }
}

Если значения перечисления смежны и вы можете предоставить первый и последний элемент перечисления, тогда:

public void EnumerateEnum()
{
    for (var i = Suit.Spade; i <= Suit.Diamond; i++)
    {
        var @enum = i;
    }
}

но это не строго перечисление, просто цикл. Второй метод намного быстрее, чем любой другой подход, хотя...

12

вот рабочий пример создания опций выбора для DDL

var resman = ViewModelResources.TimeFrame.ResourceManager;

ViewBag.TimeFrames = from MapOverlayTimeFrames timeFrame 
      in Enum.GetValues(typeof(MapOverlayTimeFrames))
      select new SelectListItem
      {
         Value = timeFrame.ToString(),
         Text = resman.GetString(timeFrame.ToString()) ?? timeFrame.ToString()
      };
10
foreach (Suit suit in Enum.GetValues(typeof(Suit)))
{
}

(В текущем принятом ответе есть бросок, который я не думаю (хотя я могу ошибаться).

9

Этот вопрос появляется в главе 10 " С# Step by Step 2013

Автор использует double for-loop для итерации через пару Enumerators (для создания полной колоды карт):

class Pack
{
    public const int NumSuits = 4;
    public const int CardsPerSuit = 13;
    private PlayingCard[,] cardPack;

    public Pack()
    {
        this.cardPack = new PlayingCard[NumSuits, CardsPerSuit];
        for (Suit suit = Suit.Clubs; suit <= Suit.Spades; suit++)
        {
            for (Value value = Value.Two; value <= Value.Ace; value++)
            {
                cardPack[(int)suit, (int)value] = new PlayingCard(suit, value);
            }
        }
    }
}

В этом случае Suit и Value являются обеими перечислениями:

enum Suit { Clubs, Diamonds, Hearts, Spades }
enum Value { Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace}

и PlayingCard - это объект карты с определенными Suit и Value:

class PlayingCard
{
    private readonly Suit suit;
    private readonly Value value;

    public PlayingCard(Suit s, Value v)
    {
        this.suit = s;
        this.value = v;
    }
}
  • 0
    будет ли это работать, если значения в enum не являются последовательными?
7

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

public static Dictionary<int, string> ToList<T>() where T : struct
{
   return ((IEnumerable<T>)Enum
       .GetValues(typeof(T)))
       .ToDictionary(
           item => Convert.ToInt32(item),
           item => item.ToString());
}

И затем:

var enums = EnumHelper.ToList<MyEnum>();
  • 0
    Dictionary не является хорошей идеей: если у вас есть Enum такой как enum E { A = 0, B = 0 } , значение 0 добавляется 2 раза, создавая ArgumentException (вы не можете добавить один и тот же Key в Dictionary 2 или более раз !).
  • 0
    Зачем возвращать Dictionary<,> из метода с именем ToList ? Также почему бы не вернуть Dictionary<T, string> ?
7

Я знаю, что это немного грязно, но если вы поклонник однострочных, вот один из них:

((Suit[])Enum.GetValues(typeof(Suit))).ToList().ForEach(i => DoSomething(i));
  • 0
    Это лисп ?
6

Что, если вы знаете, что тип будет enum, но вы не знаете, какой именно тип находится во время компиляции?

public class EnumHelper
{
    public static IEnumerable<T> GetValues<T>()
    {
        return Enum.GetValues(typeof(T)).Cast<T>();
    }

    public static IEnumerable getListOfEnum(Type type)
    {
        MethodInfo getValuesMethod = typeof(EnumHelper).GetMethod("GetValues").MakeGenericMethod(type);
        return (IEnumerable)getValuesMethod.Invoke(null, null);
    }
}

Метод getListOfEnum использует отражение для ввода любого типа перечисления и возвращает IEnumerable всех значений перечисления.

Использование:

Type myType = someEnumValue.GetType();

IEnumerable resultEnumerable = getListOfEnum(myType);

foreach (var item in resultEnumerable)
{
    Console.WriteLine(String.Format("Item: {0} Value: {1}",item.ToString(),(int)item));
}
3

Добавьте метод public static IEnumerable<T> GetValues<T>() в ваш класс, например

public static IEnumerable<T> GetValues<T>()
{
    return Enum.GetValues(typeof(T)).Cast<T>();
}

вызовите и передайте свое перечисление, теперь вы можете выполнять его итерацию с помощью foreach

 public static void EnumerateAllSuitsDemoMethod()
 {
     // custom method
     var foos = GetValues<Suit>(); 
     foreach (var foo in foos)
     {
         // Do something
     }
 }
0

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

(На самом деле, это немного сложнее, чем перечисленные типы enum, как полагают, имеют "базовый" целочисленный тип, что означает, что каждое значение перечисления соответствует целочисленному значению (обычно это неявное, но может быть указано вручную). С# был разработан таким образом, чтобы вы могли вставить любое целое число этого типа в переменную enum, даже если это не "именованное" значение.)

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

РЕДАКТИРОВАТЬ: должен был предложить метод System.Enum.GetValues вместо этого. К сожалению.

  • 2
    Хотя ваш ответ верен сам по себе, он на самом деле не отвечает первоначальному вопросу ОП. Метод GetNames возвращает строковый массив, но OP требует перечислитель через значения.
  • 0
    @SilviuPreda: Отредактировано. Это должен был быть GetValues вместо GetNames.
0

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

typeof(Suit).GetMembers(BindingFlags.Public | BindingFlags.Static)
    .ToList().ForEach(x => DoSomething(x.Name));

Ещё вопросы

Сообщество Overcoder
Наверх
Меню