简化处理标志枚举的多个ifs

时间:2011-03-10 17:27:27

标签: c# refactoring

我有一些像这样的代码:

[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

2 个答案:

答案 0 :(得分: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;
    }
}

答案 1 :(得分: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语句,并且比一次循环遍历所有位更快。您需要进行一些性能测量以查看临界点的位置,但我希望它可以低至6或7个标记(低,查找可能比执行6或7个单独的测试更快)