枚举中定义的项目总数

432

如何获取枚举类型中定义的项目数量?

12个回答

587
你可以使用静态方法Enum.GetNames,它返回一个表示枚举中所有项名称的数组。该数组的长度属性等于枚举定义的项目数。
var myEnumMemberCount = Enum.GetNames(typeof(MyEnum)).Length;

1
同意...这是我找到的链接http://www.csharp411.com/c-count-items-in-an-enum/ - Rashmi Pandit
13
也可以使用 Enum.GetValues。 - Xonatron
6
如果你没有包括System命名空间,那就需要使用System.Enum.GetNames方法来获取枚举类型的所有名称。 - Brett Pennings
9
今天我再次遇到了这个问题;在其他下面的答案中描述的C语言技巧被列为有问题的,但是如上所述的Enum.GetValues和Enum.GetNames似乎存在风险分配一个全新的数组仅以获得固定长度,这似乎…嗯,很可怕。有人知道这种方法是否确实会产生动态分配吗?如果是这样,在某些用例中,它似乎是最高效的解决方案,如果不是最灵活的解决方案。 - J Trana
@Xonatron,根据我的测试结果,GetNames 的性能比GetValues快了10倍,不知道是为什么。 - saastn
2
@JTrana 是的,我刚刚追踪了一些意外的分配,确切地说是在循环条件中通过Enum.GetNames反复获取此长度(因为它在属性的getter中,所以一眼看去并不明显)。因此,至少要确保在第一次获取时将该值缓存到某个地方。很遗憾我们无法将其作为编译时常量获取。 - atkins

198

问题是:

如何获取枚举中定义的项数?

“项数”可能真正意味着两个完全不同的东西。考虑以下示例。

enum MyEnum
{
    A = 1,
    B = 2,
    C = 1,
    D = 3,
    E = 2
}

MyEnum中定义的"items"数量是多少?

项目的数量是5吗?(A, B, C, D, E)

还是3个?(1, 2, 3)

可以按以下方式计算出在MyEnum中定义的名称数目 (5)。

var namesCount = Enum.GetNames(typeof(MyEnum)).Length;

可以按照以下方法计算MyEnum中定义的数量(3)。

var valuesCount = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Distinct().Count();

2
另一种编写最后一行的方式是 var valuesCount = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).Distinct().Count(); - Jeppe Stig Nielsen
14
我认为我没有见过任何开发者会确认这个枚举包含三项。 - motoDrizzt
2
@motoDrizzt,你可以在打印机驱动程序的枚举中找到类似这样的内容,例如 Default = 1, A4 = 1, Portrate = 1, A4Portrait = 1, Landscape = 2, A4Landscape = 2, ... ;)。 - shA.t
@Timothy Shields,最好说“不同的值”而不是仅仅说“值”。 - Dave Thompson

84

13
使用 GetNames 方法更快。 - Kasper Holdum
@KasperHoldum 你是在紧密循环中多次运行它吗?因为我的下一个问题会是,为什么这样做呢? - arkon

40

我今天进行了基准测试,并得出了有趣的结果。在这三个之间:

var count1 = typeof(TestEnum).GetFields().Length;
var count2 = Enum.GetNames(typeof(TestEnum)).Length;
var count3 = Enum.GetValues(typeof(TestEnum)).Length;

GetNames(enum)是目前最快的!

|         Method |      Mean |    Error |   StdDev |
|--------------- |---------- |--------- |--------- |
| DeclaredFields |  94.12 ns | 0.878 ns | 0.778 ns |
|       GetNames |  47.15 ns | 0.554 ns | 0.491 ns |
|      GetValues | 671.30 ns | 5.667 ns | 4.732 ns |

在使用DeclaredFields时要小心;对于一个带类型的枚举,使用该方法会添加一个额外的“SpecialName”条目,其中包含枚举的类型(例如Int32)。这会比预期增加一个额外的计数。 - Paul W

21

我在一篇 C 语言问题的答案中看到了一个巧妙的技巧,只需向枚举添加最后一个元素,并使用它来表示枚举中有多少个元素:

enum MyType {
  Type1,
  Type2,
  Type3,
  NumberOfTypes
}

如果您定义的起始值不是0,您可以使用NumberOfTypes - Type1来确定元素的数量。

我不确定这种方法是否比使用Enum更快,也不确定是否被认为是正确的做法,因为我们有Enum可以为我们确定这些信息。


1
这很好,因为我可以在XNA上做到这一点,因为GetNames在那里不可用。 - Thiago Valle
这个酷技巧也比GetNames()更快,因为它不需要计算它们的数量。 - Jordan LaPrise
7
注意不要使用foreach循环枚举类型的代码 - 否则可能会读取超出数组末尾的内容! - Michael Dorgan
4
注意枚举类型定义自己的值 - 我经常使用枚举类型来表示位标志。 - Matt Parkins
2
还要注意一些 WPF 控件,比如 ComboBox 和 ListBox,不要直接绑定枚举。 - mcy
显示剩余2条评论

10
你可以使用 Enum.GetNames 返回枚举中的值的 IEnumerable,然后使用 Count 计算结果的 IEnumerable。 GetNames 产生的结果与 GetValues 大致相同,但速度更快。

6

从之前的答案中,只需添加代码示例。

 class Program
    {
        static void Main(string[] args)
        {
            int enumlen = Enum.GetNames(typeof(myenum)).Length;
            Console.Write(enumlen);
            Console.Read();
        }
        public enum myenum
        {
            value1,
            value2
        }
    }

5

如果你像我一样经常写上面的解决方法,那么你可以将其实现为一个通用函数:

public static int GetEnumEntries<T>() where T : struct, IConvertible 
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("T must be an enumerated type");

    return Enum.GetNames(typeof(T)).Length;
}

3

对于Visual Basic:

[Enum].GetNames(typeof(MyEnum)).Length对我无效,但[Enum].GetNames(GetType(Animal_Type)).length有效。


为什么要踩我?这个解决了我的问题,它是 VB 的正确语法,即使问题标记为 C#,仍然有用。 - M Granja
2
下降分可能是因为问题被标记为C#,而此答案没有提到它没有使用C#。 - idbrii

1
我刚刚查看了这个内容,对当前解决方案的可读性并不满意。如果您是非正式地编写代码或在小型项目上编写代码,则可以在枚举末尾添加另一个项目名为"Length"。这样,您只需要键入:
var namesCount = (int)MyEnum.Length;

当然,如果其他人要使用你的代码,或者在我这种情况不适用的许多其他情况下,这个解决方案可能从不明智到可怕不等。

3
这也依赖于枚举从0开始(默认值,但并不保证)。此外,它使得普通枚举用法的智能感知非常混乱。这几乎总是一个糟糕的想法。 - BradleyDotNET
2
这没花多少时间 :) - EnergyWasRaw
1
有趣,我想你永远不知道什么时候会出现更好的东西。尽管我努力回避自己的解决方案,但发现它足够有趣,值得分享! - EnergyWasRaw
1
可以说,如果您的用例与枚举以0开头的情况相匹配,那么这条路线可能是最有效的。但请不要称其为“Length”...我使用COUNT,这样它在智能感知世界中很突出。我通常也会将ERROR用作默认值,这样在预先设置所有内容都可以为空的世界中,当某些内容未设置时就很明显了。 - Peter Drier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接