Pytanie Jak wymienić wyliczenie?


Jak wyliczyć enum w języku C #?

Na przykład. następujący kod nie kompiluje się:

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

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

I daje następujący błąd podczas kompilacji:

"Suit" to "typ", ale jest używany jako "zmienna"

Nie działa na Suit słowo kluczowe, drugie.


3119
2017-09-19 20:34


pochodzenie


Zobacz też ... stackoverflow.com/questions/972307/... - SteveC
@ChaseMedallion Twój link wydaje się być martwy. - Clearer
Możesz chcieć sprawdzić tajniki wyrażeń C #, który omawia to, a także inne użyteczne enum pożywienie - ChaseMedallion
@ Podziękowania dzięki zaktualizowałem link. - ChaseMedallion


Odpowiedzi:


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

3896
2017-09-19 20:37



To nie działa, jeśli masz zduplikowane wartości na liście wyliczeniowej. - Jessy
Chcę tylko zwrócić uwagę, że to niestety nie zadziała w silverlight, ponieważ biblioteka silverlight nie zawiera enum.GetValues. Musisz użyć refleksji w tym przypadku. - Giacomo Tagliabue
@Jessy to robi działa w przypadku powtarzających się sytuacji, takich jak enum E {A = 0, B = 0}. Enum.GetValues zwraca dwie wartości, ale są one takie same. E.A == E.B jest prawdą, więc nie ma różnicy. Jeśli chcesz mieć indywidualne imiona, powinieneś poszukać Enum.GetNames. - nawfal
Jeśli masz duplikaty / synonimy w swoim wyliczeniu, a chcesz inne zachowanie, możesz użyć Linq Distinct rozszerzenie (od .NET 3.5), czyli foreach (var suit in ((Suit[])Enum.GetValues(typeof(Suit))).Distinct()) { }. - Jeppe Stig Nielsen
Popełniłem błąd, próbując użyć var dla typu. Kompilator utworzy zmienną an Object zamiast wyliczenia. Wyświetlaj wyraźnie typ wyliczeniowy. - jpmc26


Wydaje mi się, że naprawdę chcesz wydrukować nazwy wszystkich wyliczeń, a nie wartości. W którym to przypadku Enum.GetNames() wydaje się być właściwym podejściem.

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

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

Przy okazji, 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.

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

public void PrintAllSuits()
{
    foreach (var suit in Enum.GetValues(typeof(Suits)))
    {
        System.Console.WriteLine(suit.ToString());
    }
}

562
2017-09-19 20:39





Zrobiłem kilka rozszerzeń ułatwiających wyliczanie, może ktoś może z tego skorzystać ...

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ć udekorowany FlagsAttribute

[Flags]
public enum EnumExample
{
    ValueA = 1,
    ValueB = 2,
    ValueC = 4,
    ValueD = 8,
    Combi = ValueA | ValueB
}

287
2018-06-03 12:03



Jedna liniówka dla pierwszej metody rozszerzenia; nie jest już leniwy. return Enum.GetValues ​​(typeof (T)). Cast <T> (); - Leyu
Alternatywnie możesz użyć również OfType: Enum.GetValues ​​(typeof (T)) .TypeTT <T> (). Szkoda, że ​​nie ma ogólnej wersji GetValues ​​<T> (), to byłoby jeszcze bardziej zręczne. - jpierson
Może ktoś może pokazać, jak korzystać z tych rozszerzeń? Kompilator nie wyświetla metod rozszerzenia w enumExample enum. - Tomas
Czy ktoś może dodać przykład korzystania z tych funkcji? - Ashwini Verma
+1 dla kodu wielokrotnego użytku: przykłady - zapisz te metody rozszerzenia w bibliotece i odwołaj się do nich [flagi] publiczne wyliczenie mytypes {nazwa1, nazwa2}; List <string> myTypeNames = mytypes.GetAllItems (); - Krishna


Niektóre wersje architektury .NET nie obsługują Enum.GetValues. Oto dobry sposób obejścia tego problemu Pomysły 2.0: Enum.GetValues ​​w 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;
}

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


147
2017-09-03 18:48



Dlaczego nie użyć słowa kluczowego yield tutaj, zamiast tworzyć listę? - Eric Mickelsen
lub krótszy: return type.GetFields().Where(x => x.IsLiteral).Select(x => x.GetValue(null)).Cast<Enum>(); - nawfal
@nawfal: Linq nie jest dostępny .Net CF 2.0. - Gabriel GM
@Ekevoo Jak powiązać wartości wyliczeniowe z DropDownList w MVC? - Clint Eastwood


Myślę, że jest to bardziej skuteczne 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 kompilacji, a nie wyjątek środowiska wykonawczego, jeśli Suit nie 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]);
        }
    }
}

85
2018-02-02 13:36



Uważaj przy użyciu takich generycznych programów jak ten. Jeśli spróbujesz użyć EnumLoop z jakimś typem, który nie jest wylicznikiem, będzie kompilował dobrze, ale wyrzuci wyjątek w czasie wykonywania. - svick
Dziękuję svick. Wyjątki środowiska wykonawczego będą występować wraz z innymi odpowiedziami na tej stronie ... z wyjątkiem tego, ponieważ dodałem "where Key: struct, IConvertible", aby w większości przypadków uzyskać błąd czasu kompilacji. - James
Nie, GetValues ​​() jest wywoływane tylko raz w foreach. - Alex Blokha
James, zniechęciłbym twoją klasę, ponieważ sprytny jest miły w pisaniu, ale w kodzie produkcyjnym, który wiele osób będzie utrzymywać i aktualizować, sprytna jest dodatkowa praca. Jeśli przyniesie znaczną oszczędność lub będzie dużo używana - więc oszczędności są duże i ludzie się z tym zapoznają - warto, ale w większości przypadków spowalnia to ludzi, którzy próbują czytać i aktualizować kod oraz wprowadza możliwe źródła błędów w przyszłości. Mniej kodu jest lepsza :) Mniejsza złożoność jest jeszcze lepsza. - Grant M
@James Czy mógłbyś podać przykład dla wiązania tych wartości wyliczeniowych do DropDownList w MVC? - Clint Eastwood


Dlaczego nikt nie używa Cast<T>?

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

Proszę bardzo IEnumerable<Suit>.


82
2018-03-17 04:15



To całkiem fajne, jeśli możesz użyć LINQ ... - MemphiZ
Działa to również w from i foreach deklarator nagłówka. - Aluan Haddad


Nie dostaniesz Enum.GetValues() w Silverlight.

Oryginalny post na blogu autorstwa Einara 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();
    }
}

68
2017-11-17 01:29



Fajne rozwiązanie, ale niektóre refaktoryzacje będą lepsze! :) - nawfal
@AubreyTaylor Czy możesz podać przykład do wiązania wartości wyliczeniowych do DropDownList w MVC? - Clint Eastwood
Używam pracy .NET framework 4.0 i silverlight enum.getvalues, kod, którego użyłem to ---> enum.GetValues ​​(typeof (enum)) - Ananda
Począwszy od wersji C # 7.3 (Visual Studio 2017 ≥ v15.7), można użyć where T: Enum - Yahoo Serious