2011-03-10 61 views
2

我有一些這樣的代碼:簡化多IFS處理標誌枚舉

[Flags] 
public enum someEnumFlag : long 
... 

if (someFlagEnum) 
    if (!foo()) return; 
if (someFlagEnum) 
    if (!bar()) return; 
// repeat similar lines... 

對於每個someFlagEnum,有些方法被調用,它返回一個bool。如果任何返回值爲false,則整個操作失敗。因此return

我該如何簡化?我希望那個「過早返回」部分保持完好,所以我不認爲foreach在這裏是可行的。 (糾正我,如果我錯了)

注:這someFlagEnum是非常大的(20 +標誌)。

已編輯的代碼。是的,那個枚舉真的是System.Enum

+0

爲什麼會使用'foreach'影響你使用'return'語句並提前退出的能力? – 2011-03-10 17:30:23

+0

如果我錯了,請糾正我。 – lifeweaver 2011-03-10 17:35:35

+0

'someFlagEnum'是一個真正的'System.Enum'類型嗎? – 2011-03-10 17:44:27

回答

3

如果你有很多這些flagenum值和相應的函數調用,您可以減少代碼大小和使用字典查找作爲稀疏陣列執行時間:

// set this up in advance of evaluation. Reuse across multiple evals 
    var lookup = new Dictionary<int, Func<bool>>(); 
    lookup.Add(flag1,() => foo()); 
    lookup.Add(flag2,() => bar()); 
    lookup.Add(flag1 | flag2,() => foo() && bar()); 
    // etc... 

對於標誌的每一個組合,則添加調用每個的相應功能,並返回邏輯及其結果lambda函數,用布爾短路評價。這是一個有點麻煩建立,但回報是通過評價:

// on evaluation, do this: 
    var func = lookup[someFlagEnum]; // all bits considered at the same time 
    if (!func()) // all (and only) the corresponding test functions called together 
     return; 

有開銷的哈希查找和匿名函數調用少量的,但如果你有很多標誌,你」重新測試和調用函數,我期望這種查找方法比if語句或者if語句執行更好的表達,並且比每次循環遍歷所有位更快。您需要進行一些性能測量以查看引爆點的位置,但我預計它可能會低至6或7個標記(低值,查找可能比執行6或7個獨立測試更快)

+0

謝謝。很有幫助。 – lifeweaver 2011-03-10 18:17:07

+0

如果枚舉有標誌並且有20+枚舉,則設置標誌組合的查找將成爲皮塔餅。很好的解決方案。我只是準備使用反射發佈解決方案,但強類型方法使這更好。不錯的工作。 +1 – 2011-03-10 18:36:59

+0

對於大量標誌組合,查找字典可以在代碼中生成以減少安裝的手工勞動。而不是在一個表達式中使用一個包含所有測試函數調用的lambda函數,您可以將它們分開並將它們組合在一起。運行時效率略低。使用表達式樹來構建函數調用表達式在運行時與手寫表達式一樣高效。 – dthorpe 2011-03-10 23:52:53

4
if (
    (someFlagEnum1 && !foo1()) || 
    (someFlagEnum2 && !foo2()) || 
    (someFlagEnum3 && !foo3()) || 
    (someFlagEnum4 && !bar4()) || 
    (someFlagEnum5 && !bar5()) || 
    (someFlagEnum6 && !bar6()) || 
    (someFlagEnum7 && !bar7()) || 
    (someFlagEnum8 && !bar8()) 
) 
{ 
    return; 
} 

更簡單,更難讀!混淆C#的道路從這裏開始! :-) :-)

解決方法二(C#4.0,適用於其他變種):

var conditions = new Tuple<Func<bool>, Func<bool>>[] { 
    new Tuple<Func<bool>, Func<bool>>(() => someFlagEnum.flag1,() => foo1()), 
    new Tuple<Func<bool>, Func<bool>>(() => someFlagEnum.flag2,() => foo2()), 
    new Tuple<Func<bool>, Func<bool>>(() => someFlagEnum.flag3,() => foo3()), 
    new Tuple<Func<bool>, Func<bool>>(() => someFlagEnum.flag4,() => foo4()), 
    new Tuple<Func<bool>, Func<bool>>(() => someFlagEnum.flag5,() => foo5()) 
} 

foreach (var cond in conditions) { 
    if (cond.Item1() && !cond.Item2()) { 
     return; 
    } 
} 
+0

感謝您的編輯,但我想看看是否有其他方式,直到我接受你的答案爲止。 :) – lifeweaver 2011-03-10 17:47:16