当我声明枚举时,我经常添加一个NOT_SET = 0值来知道实例何时尚未初始化。当我枚举这样一个枚举的值时(如here和here所述),丢弃NOT_SET值的最佳方法是什么?我能想到的最好的是
Enum.GetValues(typeof(T)).Cast<int>().Where(item => (0 != (int)item)).Cast<T>();
我不喜欢它,因为所有Cast&lt;&gt;的迭代次数过多。我更喜欢基于
的东西(T[]) Enum.GetValues(typeof(T))
没有所有Cast&lt;&gt ;.
答案 0 :(得分: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
为枚举的基础上。
您可以使用各种选项来提高性能,避免每次都创建阵列等。我们不知道这段代码的性能如何,所以我没有在这里详细介绍
答案 1 :(得分: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 , ... }
在我看来,如果不知道所讨论的枚举的潜在语义,你就不能做你想做的事情,最终不会在脚下射击。
答案 2 :(得分:1)
我不喜欢它,因为所有Cast&lt;&gt;的迭代次数过多。
您的陈述表明您误解了正在发生的事情。您会发现,如果您下载源代码并启用.NET Framework源步进,那么您提到的“所有迭代”就不会发生。 LINQ将您的表达式转换为单个循环。
当然,这是一个比你自己写的更复杂的循环,但肯定不是创建一个整数集合,然后创建一个枚举集合。