帮助重构此C#函数


Help refactoring this C# function

我编写的函数如下:

1
2
3
4
5
6
7
8
9
10
bool IsDry(bool isRaining, bool isWithUmbrella) {
    if (isRaining) {
        if (isWithUmbrella)
            return true;
        else
            return false;
    }
    else
        return true;
}

我需要检查一下,如果下雨的话,那么这个人需要带把雨伞来保持干燥(不要笑,这只是一个例子,我们的实际业务规则比这更严重)。

我如何重构这个,因为现在它看起来很笨拙。

谢谢你的帮助,伙计们!=)


您试图执行的业务规则是:

1
P IMPLIES Q

这在逻辑上等同于:

1
(NOT P) OR Q

因此,您可以简单地写:

1
2
3
bool IsDry(bool isRaining, bool isWithUmbrella) {
    return !isRaining || isWithUmbrella;
}

消极思考

根据谓词的不同,先从否定的角度考虑也可能更简单。

1
NOT (P IMPLIES Q)

我们现在用上述身份进行替换:

1
NOT ((NOT P) OR Q)

现在我们可以应用德莫根定律:

1
P AND (NOT Q)

既然这是否定的,我们必须否定它才能回到肯定的状态。一开始,双重否定似乎令人困惑,但回到这个例子,我们有:

1
2
3
4
bool IsDry(bool isRaining, bool isWithUmbrella) {
    bool isWet = (isRaining && !isWithUmbrella);
    return !isWet;
}

附加提示

下面是一些常见的boolean表达式重写示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
BEFORE                                  | AFTER
________________________________________|________________________________________
                                        |
if (condition == true) ...              | if (condition) ...
________________________________________|________________________________________
                                        |
if (condition == false) ...             | if (!condition) ...
________________________________________|________________________________________
                                        |
if (condition) {                        | return condition;
    return true;                        |
} else {                                |
    return false;                       |
}                                       |
________________________________________|________________________________________
                                        |
if (condition1) {                       | return (condition1 && condition2
   if (condition2) {                    |             && condition3);
      if (condition3) {                 |
         return true;                   |
      } else {                          |
         return false;                  |
      }                                 |
   } else {                             |
      return false;                     |
   }                                    |
} else {                                |
   return false;                        |
}                                       |
________________________________________|________________________________________
                                        |
return (condition1 && !condition2) ||   | return condition1 != condition2;
   (condition2 && !condition1);         | // or  condition1 ^ condition2;

注意,c中的预定义^是独占的或运算符,即使对于整型(即它不是求幂运算符)也是如此。预定义的&&||是执行"短路"评估的条件逻辑运算符。

也见

  • "还是"运算符?
  • 和_或运算符之间的差异是什么?
  • 关于C短路评估的最佳实践是什么?
  • 短路声明评估-是否有保证?〔C〕
  • 何时使用^运算符


1
2
3
4
bool IsDry(bool isRaining, bool isWithUmbrella)
{
    return (!isRaining || isWithUmbrella);
}


1
2
3
4
bool IsDry(bool isRaining, bool isWithUmbrella)
{
    return !isRaining || isWithUmbrella;
}


我通常采用的方法是连续改进。例如,先消除内部,否则:

1
2
3
4
5
6
bool IsDry(bool isRaining, bool isWithUmbrella) {
    if (isRaining)
        return isWithUmbrella;
    else
        return true;
}

然后折叠if

1
2
3
bool IsDry(bool isRaining, bool isWithUmbrella) {
    return isRaining ? isWithUmbrella : true;
}

这是一张真理表:

1
2
3
4
5
isRaining    isWithUmbrella    isWet    isDry
true         true              false    true
true         false             true     false
false        true              false    true
false        false             false    true

有一个答案可能是:

1
2
var isWet = isRaining && !isWithUmbrella;
return !isWet;


How can I refactor this

进行单元测试。

说真的。有两个布尔输入,所以您只需要四个单元测试就可以完全覆盖这个方法。

然后,在已经有了完整的分支覆盖的情况下,您可以随意使用实现。尝试一些看似正确的东西(我发现在本例中编写一个真值表非常有帮助),并且测试将告诉您是否有错误的细节。

作为进一步的好处,您可以永远保留测试,作为方法实际功能的文档。如果您选择了一个聪明的实现,比如漂亮的布尔表达式,这就特别有用了——如果您试图跟踪流程,那么您可以查看测试,然后看到:"哦,我明白了——如果我通过了这个和这个,我就得到了这个。"


首先从"else return…;"语句中删除"else",这样可以得到:

1
2
3
4
5
6
if (isRaining) {
    if (isWithUmbrella)
        return true;
    return false;
}
return true;

有点逻辑性……

1
2
3
4
5
6
7
if (isRaining) {
//    return (isWithUmbrella) ?
//        true :
//        false;
    return isWithUmbrella;
}
return true;

然后,您可以快速地将其放入一个简单的返回语句中…

1
2
3
//return (isRaining) ? isWithUmbrella : true;
//return (!isRaining) ? true : isWithUmbrella;
return (!isRaining) || isWithUmbrella;

只需单击六次,resharper就可以将代码简化为一行。

前三次单击将变形

1
2
3
4
 if (isWithUmbrella)
                    return true;
                else
                    return false;

进入之内

1
return isWithUmbrella;

接下来的三次点击变了

1
2
3
4
5
6
    if (isRaining)
    {
        return isWithUmbrella;
    }
    else
        return true;

进入之内

1
    return !isRaining || isWithUmbrella;

瞧,你完了。


1
2
3
bool IsDry(bool isRaining, bool isWithUmbrella) {
 return isRaining ? isWithUmbrella : true;
}

很明显

bool不下雨还带伞

-)