Jak wyliczyć wyliczenie

3765

Jak wyliczyć enumw C #?

Np. Poniższy kod się nie kompiluje:

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

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

Daje to następujący błąd czasu kompilacji:

„Kolor” jest „typem”, ale jest używany jak „zmienna”

Nie działa na Suitsłowo kluczowe, drugie.

Ian Boyd
źródło
17
Zobacz także ... stackoverflow.com/questions/972307/…
SteveC
2
Możesz sprawdzić tajniki C # , w których omawia się to, a także inne przydatne ciekawostki
wyliczające

Odpowiedzi:

4613
foreach (Suit suit in (Suit[]) Enum.GetValues(typeof(Suit)))
{
}

Uwaga : rzutowanie na (Suit[])nie jest absolutnie konieczne, ale przyspiesza kod o 0,5 ns .

jop
źródło
97
To nie działa, jeśli masz zduplikowane wartości na liście modułu wyliczającego.
Jessy,
10
Chcę tylko zaznaczyć, że to niestety nie będzie działać w Silverlight, ponieważ biblioteka Silverlight nie obejmuje enum.GetValues. W tym przypadku musisz użyć refleksji.
Giacomo Tagliabue
146
@Jessy to robi pracę w przypadku duplikatów takich sytuacjach enum E {A = 0, B = 0}. Enum.GetValuespowoduje zwrócenie dwóch wartości, chociaż są one takie same. E.A == E.Bjest prawdą, więc nie ma różnicy. Jeśli chcesz mieć indywidualne nazwy, powinieneś poszukać Enum.GetNames.
nawfal
13
Następnie, jeśli masz duplikaty / synonimy w swoim wyliczeniu i chcesz inne zachowanie, możesz użyć Distinctrozszerzenia Linq (od .NET 3.5), więc foreach (var suit in ((Suit[])Enum.GetValues(typeof(Suit))).Distinct()) { }.
Jeppe Stig Nielsen
42
Popełniłem błąd, próbując użyć vartego typu. Kompilator zmieni zmienną Objectzamiast w wyliczenie. Podaj jawnie typ wyliczenia.
jpmc26
695

Wydaje mi się, że naprawdę chcesz wydrukować nazwy każdego wyliczenia, a nie wartości. W takim przypadku Enum.GetNames()wydaje się to właściwe podejście.

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

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

Nawiasem mówiąc, zwiększanie wartości nie jest dobrym sposobem na wyliczenie wartości wyliczenia. Powinieneś to zrobić zamiast tego.

Użyłbym Enum.GetValues(typeof(Suit))zamiast tego.

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

public void PrintAllSuits()
{
    foreach (var suit in Enum.GetValues(typeof(Suits)))
    {
        System.Console.WriteLine(suit.ToString());
    }
}
Haacked
źródło
2
VB Składnia tutaj: link
AndruWitta
Wziąłem wersję z małym następujących zmian z mojej strony: Enum.GetValues(typeof(Suits)).OfType<Suits>().ToArray(). W takim przypadku mogę iterować tablicę elementów Suitswyliczeniowych, a nie ciągów.
Barabas
@Barabas dlaczego po prostu nie zrobić Suits suit in Enum.GetValues(typeof(Suits))?
themadking
@themadking oh, stary! oczywiście użycie dokładnego typu wygląda lepiej niż ten monstrualny kawałek sh ... kodu!
Barabas
337

Zrobiłem kilka rozszerzeń dla łatwego użycia enum. Może ktoś może go użyć ...

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;
    }
}

Sam enum musi być ozdobiony FlagsAttribute :

[Flags]
public enum EnumExample
{
    ValueA = 1,
    ValueB = 2,
    ValueC = 4,
    ValueD = 8,
    Combi = ValueA | ValueB
}
kok
źródło
13
Jedna wkładka do pierwszej metody przedłużania; nie jest już bardziej leniwy. return Enum.GetValues ​​(typeof (T)). Cast <T> ();
Leyu,
2
Możesz też użyć OfType: Enum.GetValues ​​(typeof (T)). OfType <T> (). Szkoda, że ​​nie istnieje ogólna wersja GetValues ​​<T> (), więc byłoby jeszcze lepiej.
jpierson
3
Może ktoś może pokazać, jak korzystać z tych rozszerzeń? Kompilator nie wyświetla metod rozszerzenia na enum EnumExample.
Tomas
1
czy ktoś może dodać przykład, jak korzystać z tych funkcji?
Ashwini Verma,
3
+1 dla kodu wielokrotnego użytku: przykłady - zapisz te metody rozszerzenia w bibliotece i odwołaj się do niego [Flagi] public enum mytypes {name1, name2}; List <string> myTypeNames = mytypes.GetAllItems ();
Krishna
178

Niektóre wersje .NET Framework nie obsługują Enum.GetValues. Oto dobre obejście od Ideas 2.0: Enum.GetValues ​​w Compact Framework :

public Enum[] GetValues(Enum enumeration)
{
    FieldInfo[] fields = enumeration.GetType().GetFields(BindingFlags.Static | BindingFlags.Public);
    Enum[] enumerations = new Enum[fields.Length];

    for (var i = 0; i < fields.Length; i++)
        enumerations[i] = (Enum) fields[i].GetValue(enumeration);

    return enumerations;
}

Podobnie jak w przypadku każdego kodu, który wymaga refleksji , powinieneś podjąć kroki, aby upewnić się, że działa tylko raz, a wyniki są buforowane.

Ekevoo
źródło
18
Dlaczego nie użyć tutaj słowa kluczowego wydajności zamiast tworzenia listy?
Eric Mickelsen,
1
lub krócej:return type.GetFields().Where(x => x.IsLiteral).Select(x => x.GetValue(null)).Cast<Enum>();
nawfal
7
@nawfal: Linq nie jest dostępny .Net CF 2.0.
Gabriel GM
@Ekevoo Jak powiązać te wartości wyliczeniowe z DropDownList w MVC?
Jack
115

Użyj Cast<T>:

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

Proszę bardzo IEnumerable<Suit>.

sircodesalot
źródło
1
Działa to również w fromklauzuli i foreachdeklaratorze nagłówka.
Aluan Haddad,
97

Myślę, że jest to bardziej wydajne niż inne sugestie, ponieważ GetValues()nie jest wywoływane za każdym razem, gdy masz pętlę. Jest również bardziej zwięzły. I pojawia się błąd czasu kompilacji, a nie wyjątek czasu wykonywania, jeśli Suitnie jest enum.

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

EnumLoop ma tę całkowicie ogólną definicję:

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]);
        }
    }
}
James
źródło
6
Ostrożnie przy użyciu takich leków generycznych. Jeśli spróbujesz użyć EnumLoopz typem, który nie jest wyliczeniem, skompiluje się dobrze, ale wygeneruje wyjątek w czasie wykonywania.
svick
7
Dziękuję svick. Wyjątki czasu wykonywania wystąpią w rzeczywistości z innymi odpowiedziami na tej stronie ... oprócz tej, ponieważ dodałem „where Key: struct, IConvertible”, aby w większości przypadków wystąpił błąd czasu kompilacji.
James
3
Nie, funkcja GetValues ​​() jest wywoływana tylko raz w foreach.
Alex Blokha
4
James, odradzałbym twoją klasę, ponieważ sprytny jest fajny do pisania, ale w kodzie produkcyjnym, który wiele osób będzie utrzymywać i aktualizować, sprytny to dodatkowa praca. Jeśli przynosi znaczne oszczędności lub będzie często wykorzystywany - oszczędności są duże, a ludzie się z nim zapoznają - warto, ale w większości przypadków spowalnia ludzi próbujących czytać i aktualizować kod oraz wprowadza możliwe błędy źródłowe w przyszłości. Im mniej kodu, tym lepiej :) mniejsza złożoność jest jeszcze lepsza.
Grant M
2
@GrantM Dlaczego? Ten kod nie jest ani skomplikowany, ani niewiarygodnie krótki. Co więcej, napisanie klasy raz pozwoli na jeszcze krótsze iteracje kodu przy użyciu zgodnie z jego przykładem. Jest to bardzo czyste, jeśli nie możesz zaktualizować tego kodu, prawdopodobnie nie możesz zaktualizować żadnego kodu firmy.
Dyspersja
77

Nie dostaniesz się Enum.GetValues()w Silverlight .

Oryginalny post na blogu autorstwa Einara Ingebrigtsena :

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();
    }
}
Aubrey Taylor
źródło
2
Ładne rozwiązanie, ale trochę refaktoryzacji będzie lepsze! :)
nawfal
Korzystam z .NET Framework 4.0 i pracy enum.getvalues ​​Silverlight, użyłem kodu ---> enum.GetValues ​​(typeof (enum))
Ananda
2
Zaczynając od C # 7.3 (Visual Studio 2017 ≥ v15.7), można używaćwhere T: Enum
Yahoo Serious
59

Moje rozwiązanie działa w .NET Compact Framework (3.5) i obsługuje sprawdzanie typów w czasie kompilacji :

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();
}
  • Jeśli ktoś wie, jak się go pozbyć T valueType = new T(), chętnie znajdę rozwiązanie.

Połączenie wyglądałoby tak:

List<MyEnum> result = Utils.GetEnumValues<MyEnum>();
Mallox
źródło
2
co z użyciem T valueType = default(T)?
Oliver,
Świetnie, nawet nie znałem tego słowa kluczowego. Zawsze miło jest nauczyć się czegoś nowego. Dziękuję Ci! Czy zawsze zwraca odwołanie do tego samego obiektu, czy tworzy nową instancję za każdym razem, gdy wywoływana jest instrukcja domyślna? Do tej pory nie znalazłem nic w sieci, ale jeśli tworzy za każdym razem nową instancję, to w pewien sposób udaremnia cel, którego szukałem (posiadanie jednej linii ^^).
Mallox
1
Czy nie stworzyłoby to nowej instancji dla każdej iteracji ponad wyliczeniem?
Mallox
1
-1 dla „obsługuje sprawdzanie typu w czasie kompilacji:”. Jakiego rodzaju sprawdzanie? To by działało dla każdego new() T. Ponadto new T()wcale nie potrzebujesz , możesz wybrać tylko pola statyczne i zrobić to .GetValue(null). Zobacz odpowiedź Aubreya.
nawfal
2
Zaczynając od C # 7.3 (Visual Studio 2017 ≥ v15.7), można używaćwhere T: Enum
Yahoo Serious
52

Myślę, że możesz użyć

Enum.GetNames(Suit)
Tom Carr
źródło
6
Enum.GetValues ​​(Suits)
Ian Boyd
50
public void PrintAllSuits()
{
    foreach(string suit in Enum.GetNames(typeof(Suits)))
    {
        Console.WriteLine(suit);
    }
}
Joshua Drake
źródło
2
Który wylicza ciąg, nie zapomnij przekonwertować tych rzeczy z powrotem na wartość wyliczenia, aby wyliczenie mogło zostać wyliczone.
Ian Boyd
1
Widzę po twojej edycji, że chcesz faktycznie operować na wyliczeniach, powyższy kod dotyczył twojego oryginalnego postu.
Joshua Drake
49
foreach (Suit suit in Enum.GetValues(typeof(Suit))) { }

Słyszałem niejasne plotki, że jest to wyjątkowo powolne. Ktoś wie? - Orion Edwards, 15 października 2008 o 1:31 7

Myślę, że buforowanie tablicy znacznie przyspieszy. Wygląda na to, że za każdym razem otrzymujesz nową tablicę (poprzez odbicie). Raczej:

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

To przynajmniej trochę szybciej, ja?

Ograniczone Zadośćuczynienie
źródło
5
Kompilator powinien się tym jednak zająć.
Stephan Bijzitter
@StephanBijzitter Wow, czytasz dość daleko na ten temat :-) Zgadzam się, kompilator powinien sprawić, że moje rozwiązanie nie będzie konieczne.
Ograniczone Zadośćuczynienie
1
To nie jest konieczne. Patrząc na skompilowany kod w ILSpy, kompilator zdecydowanie już to robi. Dlaczego ta odpowiedź jest w ogóle oceniana, a tym bardziej 35 razy?
mhenry1384
1
Już dawno zostało to ocenione. Bardzo dawno temu. Założę się, że kompilator również wtedy to rozwiązał. Ale na pewno wygląda bardziej wydajnie, prawda? ;-)
Ograniczone Zadośćuczynienie
32

Trzy drogi:

  1. Enum.GetValues(type) // Od .NET 1.1, nie w Silverlight ani .NET Compact Framework
  2. type.GetEnumValues() // Tylko w .NET 4 i nowszych
  3. type.GetFields().Where(x => x.IsLiteral).Select(x => x.GetValue(null)) // Działa wszędzie

Nie jestem pewien, dlaczego GetEnumValueszostał wprowadzony w instancjach typu. Dla mnie to wcale nie jest bardzo czytelne.


Posiadanie klasy pomocniczej Enum<T>jest dla mnie najbardziej czytelne i niezapomniane:

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

Teraz dzwonisz:

Enum<Suit>.GetValues();

// Or
Enum.GetValues(typeof(Suit)); // Pretty consistent style

Można również użyć pewnego rodzaju buforowania, jeśli wydajność ma znaczenie, ale nie spodziewam się, że będzie to w ogóle problem.

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)));
    }
}
nawfal
źródło
To miłe podsumowanie metod. Myślę jednak, że powinieneś połączyć w to swoją drugą odpowiedź. Prawda jest taka, że ​​wyliczenia są wyjątkowe, a ich przeglądanie jest często (zwykle) tak samo ważne jak wyliczenie, ponieważ wiesz, że wartości nigdy się nie zmienią. IOW, jeśli masz wyliczanie, które cały czas się zmienia, to na początek wybrałeś niewłaściwą konstrukcję danych.
krowe2
31

Po prostu łącząc najlepsze odpowiedzi, stworzyłem bardzo proste rozszerzenie:

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 T value) where T : Enum
    {
        return (T[])Enum.GetValues(typeof (T));
    }
}

Jest czysty, prosty i, według komentarza @ Jeppe-Stig-Nielsen, szybki.

Ciemna strona
źródło
6
Począwszy od C # 7.3 (Visual Studio 2017 ≥ v15.7), można używaćwhere T: Enum
Yahoo Serious
24

Istnieją dwa sposoby iteracji Enum:

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

Pierwszy da ci wartości w formie na tablicy ** object** s, a drugi da ci wartości w postaci tablicy **String ** s.

Użyj go w foreachpętli, jak poniżej:

foreach(var value in values)
{
    // Do operations here
}
Kylo Ren
źródło
2
Może dlatego, że jest to już zawarte w wielu odpowiedziach? Nie pozwólmy, aby odpowiedzi były zbędne.
nawfal
@nawfal tak może być ujęte w innych odpowiedziach, choć w większości z nich nie jest dobrze zakończone.
Kylo Ren
23

Używam ToString (), a następnie dzielę i analizuję tablicę pluć w flagi.

[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);
}
Mickey Perlstein
źródło
17

Nie uważam, że to jest lepsze, a nawet dobre. Podaję tylko inne rozwiązanie.

Jeśli wartości wyliczeniowe mieszczą się w zakresie od 0 do n - 1, ogólną alternatywą jest:

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

Jeśli wartości wyliczenia są ciągłe i możesz podać pierwszy i ostatni element wyliczenia, to:

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

Ale to nie jest ściśle wyliczenie, tylko zapętlenie. Druga metoda jest jednak znacznie szybsza niż jakiekolwiek inne podejście ...

nawfal
źródło
16

Jeśli potrzebujesz sprawdzania prędkości i typu w czasie kompilacji i wykonywania, ta metoda pomocnicza jest lepsza niż użycie LINQ do rzutowania każdego elementu:

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[];
}

I możesz użyć go jak poniżej:

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

Oczywiście możesz wrócić IEnumerable<T>, ale to nic tu nie kupi.

dmihailescu
źródło
3
Począwszy od C # 7.3 (Visual Studio 2017 ≥ v15.7), można używaćwhere T: Enum
Yahoo Serious
14

Oto działający przykład tworzenia wybranych opcji dla 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()
      };
jhilden
źródło
10
foreach (Suit suit in Enum.GetValues(typeof(Suit)))
{
}

(Akceptowana obecnie odpowiedź zawiera obsadę, która moim zdaniem nie jest potrzebna (chociaż mogę się mylić).)

matowe oparzenia
źródło
10

To pytanie pojawia się w rozdziale 10 „ C # krok po kroku 2013

Autor używa podwójnej pętli for do iteracji przez parę urządzeń wyliczających (aby utworzyć pełną talię kart):

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

W tym przypadku Suiti Valueoba są wyliczeniami:

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

i PlayingCardjest obiektem karcianym o zdefiniowanym Suiti Value:

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

    public PlayingCard(Suit s, Value v)
    {
        this.suit = s;
        this.value = v;
    }
}
Ross Gatih
źródło
czy to zadziała, jeśli wartości w enum nie są sekwencyjne?
Aamir Masood
10

Wiem, że to trochę bałagan, ale jeśli jesteś fanem jedno-liniowych, oto jeden:

((Suit[])Enum.GetValues(typeof(Suit))).ToList().ForEach(i => DoSomething(i));
anar khalilov
źródło
2
Czy to seplenienie ?
Mikael Dúi Bolinder
8

Co jeśli wiesz, że typ będzie typu enum, ale nie wiesz, jaki dokładnie jest typ w czasie kompilacji?

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

Metoda getListOfEnumwykorzystuje refleksję do pobrania dowolnego typu wyliczenia i zwraca IEnumerablewszystkie wartości wyliczenia.

Stosowanie:

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));
}
Slappywag
źródło
8

Prosty i ogólny sposób przekonwertowania wyliczenia na coś, w co możesz wchodzić w interakcje:

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());
}

I wtedy:

var enums = EnumHelper.ToList<MyEnum>();
Gabriel
źródło
DictionaryNie jest dobrym pomysłem: jeśli masz Enumjak enum E { A = 0, B = 0 }wartość 0 dodano 2 razy generowania ArgumentException(nie można dodać takie same Keyna ciągu Dictionary2 lub więcej razy!).
Massimiliano Kraus
Po co zwracać Dictionary<,>metodę o nazwie ToList? A dlaczego nie wrócić Dictionary<T, string>?
Aluan Haddad,
8

Dodaj metodę public static IEnumerable<T> GetValues<T>()do swojej klasy, na przykład:

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

Zadzwoń i przekaż swój enum. Teraz możesz iterować za pomocą foreach:

 public static void EnumerateAllSuitsDemoMethod()
 {
     // Custom method
     var foos = GetValues<Suit>();
     foreach (var foo in foos)
     {
         // Do something
     }
 }
MUT
źródło
2

enumtypy są nazywane „typami wyliczeń” nie dlatego, że są kontenerami, które „wyliczają” wartości (którymi nie są), ale ponieważ są zdefiniowane przez wyliczanie możliwych wartości dla zmiennej tego typu.

(W rzeczywistości jest to nieco bardziej skomplikowane - typy wyliczeniowe są uważane za mające „leżącą u podstaw” liczbę całkowitą, co oznacza, że ​​każda wartość wyliczenia odpowiada wartości całkowitej (jest to zwykle niejawne, ale może być określone ręcznie). C # został zaprojektowany w taki sposób, aby można było wypchać dowolne liczbę całkowitą tego typu do zmiennej wyliczeniowej, nawet jeśli nie jest to wartość nazwana).

Metoda System.Enum.GetNames może być używany do pobierania tablicę łańcuchów, które są nazwy wartości enum, jak sama nazwa wskazuje.

EDYCJA: Powinien zamiast tego zasugerować metodę System.Enum.GetValues . Ups

Emily Chen
źródło
2
Chociaż twoja odpowiedź jest poprawna sama w sobie, tak naprawdę nie odnosi się do pierwotnego pytania PO. Te GetNamesmetody powraca rzeczywiście tablica łańcuch, a PO wymaga wyliczający przez wartości.
Silviu Preda
@SilviuPreda: Edytowane. Powinno to być GetValues ​​zamiast GetNames.
Emily Chen
2

Próbowałem na wiele sposobów i uzyskałem wynik z tego kodu:

Aby uzyskać listę int z wyliczenia, użyj następujących. To działa!

List<int> listEnumValues = new List<int>();
YourEnumType[] myEnumMembers = (YourEnumType[])Enum.GetValues(typeof(YourEnumType));
foreach ( YourEnumType enumMember in myEnumMembers)
{
    listEnumValues.Add(enumMember.GetHashCode());
}
reza akhlaghi
źródło
1
tanx do edycji @ peter-mortensen
reza akhlaghi
0

Możesz także powiązać publiczne publiczne elementy wyliczeniowe bezpośrednio, używając odbicia:

typeof(Suit).GetMembers(BindingFlags.Public | BindingFlags.Static)
    .ToList().ForEach(x => DoSomething(x.Name));
Termininja
źródło
0

Jeśli masz:

enum Suit
{
   Spades,
   Hearts,
   Clubs,
   Diamonds
}

To:

foreach (var e in Enum.GetValues(typeof(Suit)))
{
    Console.WriteLine(e.ToString() + " = " + (int)e);
}

Wyjdzie:

Spades = 0
Hearts = 1
Clubs = 2
Diamonds = 3
rlv-dan
źródło
0

Ogólny sposób LINQ :

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

Stosowanie:

        var enums = ToList<Enum>();
Erçin Dedeoğlu
źródło