2012-03-12 41 views
11

我的問題的關鍵部分是跳過。我打算使用大約20個元素的枚舉類型。我想遍歷這個集合,但每次都需要跳過一個或兩個元素。事先知道要跳過什麼。一個可比較的例子是枚舉類型,它由字母表中的所有字母組成,迭代時,我想跳過所有的元音。如何遍歷枚舉類型,同時跳過一些值?

我應該如何以優雅/有效的方式編碼迭代?我應該製作一組由元音組成的獨立元素嗎?我沒有代碼可以顯示,因爲我只是在想這個問題。

回答

27
var query = Enum.GetValues(typeof(MyEnum)) 
    .Cast<MyEnum>() 
    .Except(new MyEnum[] { MyEnum.A, MyEnum.E }); 
foreach (MyEnum item in query) { 
    ... 
} 

你需要爲了得到LINQ的魔法施放。 Except一個人不會這樣做。


UPDATE:

我有另一個想法。您可以使用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) { 
    ... 
} 

在第一解決方案的優點是查詢,你可以用一個位與操作進行測試。

您最多可以定義32個冪。如果您需要更多,則可以將枚舉的基本類型定義爲long並使用最多64個標誌值(加上現有標誌值的組合)。

[Flags] 
enum MyEnum : long 
{ 
    ... 
} 
+0

這可能是最完整的答案。最簡單的做法是指定各種你想跳過的枚舉集合,這樣你可以保存這些跳過集合,並且可以通過你想要的任何標準傳入Except。 – SPFiredrake 2012-03-12 17:42:39

+0

是的,你也可以保留各種查詢。 – 2012-03-12 17:46:03

+1

我添加了另一個解決方案,僅使用按位AND進行測試。它不需要任何數組或HashSets作爲例外值。請參閱我的更新。 – 2012-03-12 22:56:51

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