1

当我声明一个枚举时,我经常添加一个 NOT_SET = 0 值来了解实例何时尚未初始化。当我枚举这样一个枚举的值时(如herehere所述),丢弃该NOT_SET值的最佳方法是什么?我能想到的最好的办法是

Enum.GetValues(typeof(T)).Cast<int>().Where(item => (0 != (int)item)).Cast<T>();

我不喜欢它,因为所有这些 Cast<> 的迭代太多。我更喜欢基于

(T[]) Enum.GetValues(typeof(T))

没有所有 Cast<> 的。

4

3 回答 3

5

目前尚不清楚为什么你有两个 Cast<T>电话,但很容易分两步完成:

var allValues = (T[]) Enum.GetValues(typeof(T));
var allButDefault = allValues.Except(Enumerable.Repeat(default(T), 1));

假设默认比较器做正确的事情,在这里使用Except可以避免装箱。请注意,它需要构建一个集合,因此使用我的原始代码可能会更好:

var allValues = (T[]) Enum.GetValues(typeof(T));
var allButDefault = allValues.Where(t => !t.Equals(default(T)));

或者使用默认的相等比较器T

var allValues = (T[]) Enum.GetValues(typeof(T));
var comparer = EqualityComparer<T>.Default;
var allButDefault = allValues.Where(t => !comparer.Equals(t, default(T)));

请注意,所有这些也将处理非int基于枚举。

您可能还想看看我的Unconstrained Melody项目,它建立在实际约束T为枚举的想法之上。

您可以使用各种选项来提高性能,避免每次都创建数组等。我们不知道这段代码对性能有多重要,所以我没有在这里详细介绍。

于 2013-09-10T18:26:56.613 回答
1

我不喜欢它,因为所有这些 Cast<> 的迭代太多。

你的陈述表明你误解了正在发生的事情。您会发现,如果您下载源代码并启用 .NET Framework 源代码步进,那么您提到的“所有迭代”根本不会发生。LINQ 将您的表达式变成一个循环

诚然,这是一个比您自己编写的更复杂的循环,但它肯定不是创建整数集合,然后创建枚举集合。

于 2013-09-10T18:44:20.307 回答
1

您如何区分这些情况:

  • 一个声明为未知或未设置标签的枚举default(T)
    public enum Foo { Unknown = 0 , Alpha = 1 , Bravo = 2 , Charlie = 3 , }

  • 一个没有为其定义标签的枚举default(T)
    `public enum Bar { Alpha = 1 , Bravo = 2 , Charlie = 3 , }

  • 一个为其定义了标签的枚举default(T),但该标签代表一个实际的有效值?
    public enum FooBar { Alpha = 0 , Bravo = 1, Charlie = 2 , }

  • [Flags]没有设置位的枚举有意义:
    [Flags] public enum ErrorConditions { None = 0x0000 , ErrorState_X = 0x0001 , ErrorState_Y = 0x0002 , ErrorState_Z = 0x0004 , ErrorState_XY = 0x0003 , ... }

在我看来,如果不知道所讨论的枚举的基本语义,你就不能做你想做的事,除非你最终自责。

于 2013-09-10T18:40:25.497 回答