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

C# 简化处理标志枚举的多个ifs,c#,refactoring,C#,Refactoring,我有一些这样的代码: [Flags] public enum someEnumFlag : long ... if (someFlagEnum) if (!foo()) return; if (someFlagEnum) if (!bar()) return; // repeat similar lines... 对于每个someflagnum,都会调用某个方法并返回一个bool。如果任何返回值为false,则整个操作将失败。因此返回 我如何简化这一点?我希望“过早返回”部分

我有一些这样的代码:

[Flags]
public enum someEnumFlag : long
...

if (someFlagEnum)
    if (!foo()) return;
if (someFlagEnum)
    if (!bar()) return;
// repeat similar lines...
对于每个
someflagnum
,都会调用某个方法并返回一个
bool
。如果任何返回值为
false
,则整个操作将失败。因此
返回

我如何简化这一点?我希望“过早返回”部分完好无损,所以我认为foreach在这里不可行。(如果我错了,请纠正我)

注意:这个
someflagnum
非常大(20多个标志)。

编辑代码。是的,该枚举实际上是
System.enum

if (
    (someFlagEnum1 && !foo1()) || 
    (someFlagEnum2 && !foo2()) ||
    (someFlagEnum3 && !foo3()) ||
    (someFlagEnum4 && !bar4()) ||
    (someFlagEnum5 && !bar5()) ||
    (someFlagEnum6 && !bar6()) ||
    (someFlagEnum7 && !bar7()) ||
    (someFlagEnum8 && !bar8())
 )
 {
    return;
 }
更简单更不可读!通往模糊C的道路从这里开始!:-):-)

第二种解决方案(C#4.0,适用于其他变体):

var条件=新元组[]{
新元组(()=>someflagnum.flag1,()=>foo1()),
新元组(()=>someflagnum.flag2,()=>foo2()),
新元组(()=>someflagnum.flag3,()=>foo3()),
新元组(()=>someflagnum.flag4,()=>foo4()),
新元组(()=>someflagnum.flag5,()=>foo5())
}
foreach(条件中的var cond){
if(cond.Item1()&&!cond.Item2()){
返回;
}
}

如果您有很多这样的flagnum值和相应的函数调用,您可以使用字典查找作为稀疏数组来减少代码大小和执行时间:

    // 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...

散列查找和匿名函数调用有少量开销,但是如果您有很多要测试和调用函数的标志,我希望这种查找方法比成堆的if语句或带有非常大表达式的if语句执行得更好,而且比一次一个循环遍历所有位更快。您需要进行一些性能测量,以了解临界点在哪里,但我希望它可能低至6或7个标志(注意,查找可能比执行6或7个单独的测试更快)

为什么使用
foreach
会影响您使用
return
语句并提前退出的能力?如果我错了,请纠正我。
someflagnum
是一个真正的
系统。Enum
类型吗?我想您需要一个Enum和标志之间的映射。您的示例不太清楚-您说正在调用一个方法,但您的代码没有显示这一点。一个更接近真实的例子会有所帮助。编辑代码。希望我的问题现在更清楚了。谢谢你的编辑,但我想看看是否还有其他方法,直到我接受你的答案。:)如果枚举有标志,并且有20+个枚举,那么为标志组合设置查找将是一个pita。否则,这是一个很好的解决方案。我刚刚准备发布一个使用反射的解决方案,但是强类型方法使它变得更好。干得好+1对于大量的标志组合,可以在代码中生成查找字典,以减少设置的手动劳动。您可以将所有测试函数调用分解并组合在一起,而不是在一个表达式中使用一个lambda func。运行时效率稍低。使用表达式树来构建函数调用表达式在运行时与手工编写的表达式一样高效。如果20个标志很少在组合中使用,我会使用PITA并只编写20行代码来设置查找。如果这20个标志的所有组合都是可能的并且需要被表示,我会花一点时间考虑我是否真的想用内存点击来生成一个具有一百万个条目(2 ^ 20)的查找表。如果性能胜过内存消耗,那就去做吧。还有一点需要注意的是:如果这20个标志的每一个组合都是必需的,那么就不要使用字典,而是使用数组。字典更适合稀疏情况(很少组合使用20个标志),但数组更适合密集情况。数组索引是一种直接的地址偏移量计算,比字典的哈希计算和查找更快。
    // 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...
    // 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;