a

Câu hỏi Làm thế nào để tôi liệt kê một enum?


Làm thế nào bạn có thể liệt kê một enum trong C #?

Ví dụ. đoạn mã sau không biên dịch:

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

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

Và cung cấp cho các lỗi biên dịch thời gian sau đây:

'Suit' là một 'loại' nhưng được sử dụng như một 'biến'

Nó thất bại trên Suit từ khóa, từ khóa thứ hai.


3119
2017-09-19 20:34


gốc


Xem thêm ... stackoverflow.com/questions/972307/… - SteveC
@ChaseMedallion Liên kết của bạn dường như đã chết. - Clearer
Bạn có thể muốn kiểm tra các ins and outs của C # enums, thảo luận về điều này cũng như các mẩu tin hữu ích khác - ChaseMedallion
@Clearer cảm ơn tôi đã cập nhật liên kết. - ChaseMedallion


Các câu trả lời:


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

3896
2017-09-19 20:37



Điều này không hoạt động nếu bạn có các giá trị trùng lặp trong danh sách liệt kê. - Jessy
Tôi chỉ muốn chỉ ra rằng điều này, không may sẽ không hoạt động trong Silverlight, vì thư viện Silverlight không bao gồm enum.GetValues. Bạn phải sử dụng sự phản chiếu trong trường hợp này. - Giacomo Tagliabue
@Jessy này làm làm việc trong trường hợp các tình huống trùng lặp như enum E {A = 0, B = 0}. Enum.GetValues kết quả trong hai giá trị được trả về, mặc dù chúng giống nhau. E.A == E.B là đúng, vì vậy không có sự phân biệt. Nếu bạn muốn tên riêng, thì bạn nên tìm Enum.GetNames. - nawfal
Sau đó, nếu bạn có bản sao / từ đồng nghĩa trong enum của bạn, và bạn muốn các hành vi khác, bạn có thể sử dụng LINQ's Distinct mở rộng (kể từ .NET 3.5), vì vậy foreach (var suit in ((Suit[])Enum.GetValues(typeof(Suit))).Distinct()) { }. - Jeppe Stig Nielsen
Tôi đã phạm sai lầm khi cố gắng sử dụng var cho loại. Trình biên dịch sẽ tạo biến Object thay vì enum. Liệt kê loại enum một cách rõ ràng. - jpmc26


Dường như với tôi như bạn thực sự muốn in ra tên của mỗi enum, chứ không phải là các giá trị. Trong trường hợp Enum.GetNames() dường như là cách tiếp cận đúng.

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

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

Bằng cách này, tăng giá trị không phải là một cách tốt để liệt kê các giá trị của một enum. Bạn nên làm điều này để thay thế.

tôi sẽ dùng Enum.GetValues(typeof(Suit)) thay thế.

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





Tôi đã thực hiện một số phần mở rộng để sử dụng enum dễ dàng, có thể ai đó có thể sử dụng nó ...

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

Bản thân enum phải được trang trí bằng FlagsAttribute

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

287
2018-06-03 12:03



Một lớp lót cho phương pháp mở rộng đầu tiên; nó không còn lười biếng nữa. trả về Enum.GetValues ​​(typeof (T)). Cast <T> (); - Leyu
Hoặc bạn cũng có thể sử dụng OfType: Enum.GetValues ​​(typeof (T)). OfType <T> (). Nó quá tệ không có một phiên bản chung của GetValues ​​<T> () sau đó nó sẽ còn trơn tru hơn nữa. - jpierson
Có thể ai đó có thể hiển thị cách sử dụng các tiện ích mở rộng này? Trình biên dịch không hiển thị các phương thức mở rộng trên enum EnumExample. - Tomas
bất cứ ai có thể thêm ví dụ làm thế nào để sử dụng những chức năng? - Ashwini Verma
1 cho mã tái sử dụng: ví dụ - lưu các phương thức mở rộng này trong thư viện và tham chiếu nó [Flags] public enum mytypes {name1, name2}; Liệt kê <string> myTypeNames = mytypes.GetAllItems (); - Krishna


Một số phiên bản của khung công tác .NET không hỗ trợ Enum.GetValues. Đây là giải pháp tốt từ Ý tưởng 2.0: Enum.GetValues ​​trong 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;
}

Như với bất kỳ mã nào liên quan đến sự phản chiếu, bạn nên thực hiện các bước để đảm bảo nó chỉ chạy một lần và kết quả được lưu trong bộ nhớ cache.


147
2017-09-03 18:48



Tại sao không sử dụng từ khóa lợi nhuận ở đây thay vì instantiating một danh sách? - Eric Mickelsen
hoặc ngắn hơn: return type.GetFields().Where(x => x.IsLiteral).Select(x => x.GetValue(null)).Cast<Enum>(); - nawfal
@nawfal: Linq không có sẵn .Net CF 2.0. - Gabriel GM
@Ekevoo Làm thế nào để ràng buộc các giá trị enum này vào một DropDownList trong MVC? - Clint Eastwood


Tôi nghĩ điều này hiệu quả hơn các đề xuất khác vì GetValues() không được gọi mỗi khi bạn có vòng lặp. Nó cũng súc tích hơn. Và bạn nhận được một lỗi biên dịch thời gian không phải là một ngoại lệ thời gian chạy nếu Suit không phải là enum.

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

EnumLoop có định nghĩa hoàn toàn chung này:

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



Cẩn thận với việc sử dụng generics như thế này. Nếu bạn cố gắng sử dụng EnumLoop với một số loại mà không phải là một enum, nó sẽ biên dịch tốt, nhưng ném một ngoại lệ tại thời gian chạy. - svick
Cảm ơn bạn svick. Thời gian chạy ngoại lệ sẽ thực sự xảy ra với các câu trả lời khác trên trang này ... ngoại trừ cái này bởi vì tôi đã thêm "trong đó Key: struct, IConvertible" để bạn nhận được lỗi biên dịch trong hầu hết các trường hợp. - James
Không, GetValues ​​() chỉ được gọi một lần trong foreach. - Alex Blokha
James, tôi sẽ ngăn cản lớp học của bạn bởi vì thông minh là tốt đẹp để viết nhưng trong mã sản xuất mà nhiều người sẽ duy trì và cập nhật, thông minh là thêm công việc. Nếu nó tiết kiệm lớn hoặc sẽ được sử dụng rất nhiều - vì vậy tiết kiệm rất lớn và mọi người sẽ trở nên quen thuộc với nó - điều đó đáng giá, nhưng trong hầu hết các trường hợp, nó làm chậm người cố gắng đọc và cập nhật mã và giới thiệu các lỗi nguồn trong tương lai. Ít mã là tốt hơn :) ít phức tạp thậm chí còn tốt hơn. - Grant M
@ James Bạn có thể đưa ra một ví dụ cho ràng buộc giá trị enum này vào một DropDownList trong MVC? - Clint Eastwood


Tại sao không ai sử dụng Cast<T>?

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

Có bạn đi IEnumerable<Suit>.


82
2018-03-17 04:15



Điều này là khá mát mẻ nếu bạn có thể sử dụng LINQ ... - MemphiZ
Điều này cũng hoạt động trong from mệnh đề và foreach header declaration. - Aluan Haddad


Bạn sẽ không nhận được Enum.GetValues() trong Silverlight.

Bài đăng gốc của 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();
    }
}

68
2017-11-17 01:29



Giải pháp tốt đẹp, nhưng một số refactoring sẽ tốt hơn! :) - nawfal
@AubreyTaylor Bạn có thể đưa ra một ví dụ để gắn các giá trị enum này vào một DropDownList trong MVC không? - Clint Eastwood
Tôi đang sử dụng NET framework 4.0 & Silverlight enum.getvalues ​​làm việc, mã tôi sử dụng là ---> enum.GetValues ​​(typeof (enum)) - Ananda
Bắt đầu với C # 7.3 (Visual Studio 2017 ≥ v15.7), người ta có thể sử dụng where T: Enum - Yahoo Serious