题 如何枚举枚举?


你怎么能枚举一个 enum 在C#?

例如。以下代码无法编译:

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

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

并给出以下编译时错误:

'Suit'是'type',但用作'变量'

它失败了 Suit 关键字,第二个。


3119
2017-09-19 20:34


起源


也可以看看 ... stackoverflow.com/questions/972307/... - SteveC
@ChaseMedallion您的链接似乎已经死了。 - Clearer
你可能想看看 C#枚举的来龙去脉,讨论这个以及其他有用的枚举花絮 - ChaseMedallion
@Clearer谢谢我已更新链接。 - ChaseMedallion


答案:


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

3896
2017-09-19 20:37



如果枚举器列表中有重复值,则此方法无效。 - Jessy
我只是想指出,不幸的是,这不会在silverlight中起作用,因为silverlight库不包含 enum.GetValues。在这种情况下你必须使用反射。 - Giacomo Tagliabue
@Jessy这个 不 在重复情况下工作 enum E {A = 0, B = 0}。 Enum.GetValues 导致返回两个值,但它们是相同的。 E.A == E.B 是的,所以没有区别。如果你想要个人名字,那么你应该寻找 Enum.GetNames。 - nawfal
然后,如果您的枚举中有重复/同义词,并且您想要其他行为,则可以使用Linq Distinct 扩展(自.NET 3.5起),所以 foreach (var suit in ((Suit[])Enum.GetValues(typeof(Suit))).Distinct()) { }。 - Jeppe Stig Nielsen
我犯了试图使用的错误 var 对于类型。编译器将使变量成为 Object 而不是枚举。明确列出枚举类型。 - jpmc26


在我看来,你真的想要打印每个枚举的名称,而不是值。在这种情况下 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());
    }
}

562
2017-09-19 20:39





我做了一些扩展以便轻松使用枚举,也许有人可以使用它...

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
}

287
2018-06-03 12:03



用于第一种延伸方法的单衬垫;它不再是懒惰。 return Enum.GetValues(typeof(T))。Cast <T>(); - Leyu
或者你也可以使用OfType:Enum.GetValues(typeof(T))。OfType <T>()。太糟糕了,没有通用版本的GetValues <T>()那么它会更加光滑。 - jpierson
也许有人可以展示如何使用这些扩展?编译器不会在枚举EnumExample上显示扩展方法。 - Tomas
谁能添加例子如何利用这些功能? - Ashwini Verma
可重用代码的+1:示例 - 将这些扩展方法保存在库中并引用它[Flags] public enum mytypes {name1,name2}; List <string> myTypeNames = mytypes.GetAllItems(); - Krishna


某些版本的.NET框架不支持 Enum.GetValues。这是一个很好的解决方法 Ideas 2.0:Compact Framework中的Enum.GetValues

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

与任何涉及的代码一样 反射,您应该采取措施确保它只运行一次并缓存结果。


147
2017-09-03 18:48



为什么不在这里使用yield关键字而不是实例化列表? - Eric Mickelsen
或更短: return type.GetFields().Where(x => x.IsLiteral).Select(x => x.GetValue(null)).Cast<Enum>(); - nawfal
@nawfal:Linq不可用.Net CF 2.0。 - Gabriel GM
@Ekevoo如何将此枚举值绑定到MVC中的DropDownList? - Clint Eastwood


我认为这比其他建议更有效,因为 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]);
        }
    }
}

85
2018-02-02 13:36



小心使用这样的泛型。如果你试图使用 EnumLoop 某些类型不是枚举,它将编译正常,但在运行时抛出异常。 - svick
谢谢svick。运行时异常实际上会与此页面上的其他答案一起发生...除了这个,因为我已经添加了“where Key:struct,IConvertible”,因此在大多数情况下会出现编译时错误。 - James
不,GetValues()在foreach中只调用一次。 - Alex Blokha
詹姆斯,我会劝阻你的班级,因为聪明的人写得很好但是在许多人会维护和更新的生产代码中,聪明才是额外的工作。如果它节省了大量资金或将被大量使用 - 所以节省的费用很高,人们会熟悉它 - 这是值得的,但在大多数情况下,它会减慢人们试图阅读和更新代码的速度并引入可能性未来的漏洞。代码越少越好:)复杂性越低越好。 - Grant M
@James你能举一个例子来将这个枚举值绑定到MVC中的DropDownList吗? - Clint Eastwood


为什么没有人使用 Cast<T>

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

你去吧 IEnumerable<Suit>


82
2018-03-17 04:15



如果您可以使用LINQ,这非常酷... - MemphiZ
这也适用于 from 条款和 foreach 标头声明者。 - Aluan Haddad


你不会得到的 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();
    }
}

68
2017-11-17 01:29



很好的解决方案,但一些重构会更好! :) - nawfal
@AubreyTaylor你能举一个例子来将这个枚举值绑定到MVC中的DropDownList吗? - Clint Eastwood
我使用.NET framework 4.0和silverlight enum.getvalues工作,我使用的代码是---> enum.GetValues(typeof(enum)) - Ananda
从C#7.3开始(Visual Studio2017≥v15.7),可以使用 where T: Enum - Yahoo Serious


只是添加我的解决方案,它在紧凑的框架(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>();

50
2017-07-07 13:37



怎么样使用 T valueType = default(T)? - Oliver
太好了,我甚至不知道那个关键字。总是很高兴学习新东西。谢谢!它是始终返回对同一对象的引用,还是每次调用默认语句时都创建一个新实例?到目前为止,我还没有在网上发现任何东西,但是如果它每次创建一个新实例,那就有点击败了我想要的目的(有一个单行^^)。 - Mallox
.GetValue(新T())? - Jason Miesionczek
这不会为枚举的每次迭代创建一个新实例吗? - Mallox
-1表示“在编译时支持类型检查:”。什么类型检查?这适用于任何人 new()  T。另外,你不需要 new T()完全可以单独选择静态字段并执行 .GetValue(null)。见奥布里的回答。 - nawfal