我的问题的关键部分是跳过。我打算使用一个包含大约20个元素的枚举类型。我想迭代这个集合,但每次都需要跳过一个或两个元素。什么跳过是事先知道的。一个类似的例子是由字母表中的所有字母组成的枚举类型,并且在迭代时,我想跳过所有元音。
我应该如何以优雅/高效的方式编写迭代代码?我应该制作一组由元音组成的单独元素吗?我没有代码可以展示,因为我只是在想这个问题。
答案 0 :(得分:32)
var query = Enum.GetValues(typeof(MyEnum))
.Cast<MyEnum>()
.Except(new MyEnum[] { MyEnum.A, MyEnum.E });
foreach (MyEnum item in query) {
...
}
你需要施放才能获得LINQ的魔力。仅Except
不会这样做。
更新:
我有另一个想法。您可以使用FlagsAttribute
定义枚举,并将常规值定义为2的幂,使用按位左移运算符<<
最容易实现的值。从C#7.0开始,您还可以使用0b_0000_0000_0010_0000
之类的二进制文字。然后可以组合现有值以形成新值。
[Flags]
enum MyEnum
{
None = 0,
A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
D = 1 << 3,
E = 1 << 4,
...
X = 1 << 23,
Y = 1 << 24,
Z = 1 << 25,
Vowels = A | E | I | O | U
}
现在,您可以像这样制定查询
IEnumerable<MyEnum> query = Enum.GetValues(typeof(MyEnum))
.Cast<MyEnum>()
.Where(x => (x & MyEnum.Vowels) == MyEnum.None);
foreach (MyEnum item in query) {
...
}
优于第一种解决方案的优点是,您可以使用单个按位AND操作执行测试。
您最多可以定义32个2的幂。如果需要更多,可以将枚举的基本类型定义为long
,并使用最多64个标志值(加上现有标志值的组合)。
[Flags]
enum MyEnum : long
{
...
}
答案 1 :(得分:1)
我会创建一个由元音组成的单独元素集,然后使用LINQ获取两组之间的集合差异。
int[] vowels = {Letters.A, Letters.E, Letters.I, Letters.O, Letters.U};
IEnumerable<int> consonant = Enum.GetValues(typeof(Letters)).Except(vowels);
foreach (int consonant in consonants)
{
// Do something with each consonant
}
答案 2 :(得分:1)
我可能只是使用LINQ - 使用Enum.GetValues
(或使用Unconstrained Melody - 我写的类型安全的通用枚举/委托库)来获取所有值,然后表达要保留的值/跳过Where
条款。
如果您只是跳过特定值,HashSet
或类似的东西可能会有用(当然,如果您只是跳过一个值,则不值得) - 如果您根据条件跳过,然后需要一个完整的谓词。
例如:
public static IEnumerable<T> AllBut(T skipped) where T : struct
{
IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
return AllBut<T>(t => !comparer.Equals(skipped, t));
}
public static IEnumerable<T> AllBut(Func<T, bool> skipPredicate) where T : struct
{
IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
return Enum.GetValues(typeof(T))
.Cast<T>()
.Where(t => skipPredicate(t));
}