如何在C#中枚举枚举?

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

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

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

它给出了以下编译时错误:

“Suit”是“type”,但与“variable”类似

它在第二个Suit关键字上失败。


当前回答

三种方式:

Enum.GetValues(类型)//自.NET 1.1起,不在Silverlight或.NET Compact Framework中type.GetEnumValues()//仅适用于.NET 4及更高版本type.GetFields()。其中(x=>x.IsLiteral)。Select(x=>x.GetValue(null))//在任何地方都有效

我不确定为什么在类型实例上引入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)));
    }
}

其他回答

通过组合最重要的答案,我总结了一个非常简单的扩展:

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

它干净、简单,而且,根据@Jeppe Stig Nielsen的评论,速度很快。

下面是一个为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()
      };

我想你可以用

Enum.GetNames(Suit)

如果您需要在构建和运行时进行速度和类型检查,则此助手方法比使用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>,但这不会给您带来任何好处。

我认为这比其他建议更有效,因为每次循环时都不会调用GetValues()。它也更加简洁。如果Suit不是枚举,则会得到编译时错误,而不是运行时异常。

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