关于语言不可知论:单个if语句中谓词的正确平衡在哪里?

Where is the right balance of predicates in a single if statement?

我个人对以下代码没有问题

1
2
3
4
if (Object foo != null && !String.IsNullOrEmpty(foo["bar"]))
{
    // do something
}

因为我觉得下面太冗长了

1
2
3
4
5
6
7
if (Object foo != null)
{
    if (!String.IsNullOrEmpty(foo["bar"]))
    {
        // do something
    }
}

但是,如果假设有5个谓词,我必须将文本包装在编辑器中才能同时看到它们,那么我就不会使用这个观点了,是否有一条逻辑"线"可以用来表示在一个if语句中包含多少谓词,其意义与说方法不需要超过7个参数类似?


我不认为用两个语句来重写if语句是一种方法,特别是当您认为在示例中添加一个else子句会产生不同的结果时。如果我想减少条件中原子命题的数量,我将把一些有意义的因素结合到它们自己的函数中,比如:

1
if(won_jackpot(obj)) ...

我认为这是不同类型运算符和正确格式的平衡。如果所有运算符都相同(all"and"或all"or"),则可以将不定数量的表达式连接在一起,而不会失去理解:

1
2
3
4
5
6
7
8
9
10
11
12
if (something() &&
    something_else() &&
    so_on() &&
    so_forth() &&
    some_more_stuff() &&
    yada() &&
    yada() &&
    yada() &&
    newman() &&
    soup_nazi() &&
    etc())
  ...


短期记忆有七个项目的容量,给或取两个。这意味着一个包含五个以上不同对象的表达式可能需要暂停并考虑它。


我不相信有什么神奇的数字。如果所有谓词在一起都有意义,那么我将把它们放在一起。这可能涉及将if语句拆分为两行,但我通常不会引入多余的额外if语句。但如果时间特别长,你应该问问自己,所有的陈述是否真的是必要的。也许您可以更早地过滤掉一些值或类似的值。最大的问题是可读性。如果其他人很难理解,您需要重构代码。但是,将代码分成两个不同的if语句很少能使代码更具可读性,它只需要占用更多的行。


这取决于你在做什么。第二条语句在您反转时产生不同的结果。(在其前面添加一个"not"),这是非常常见的bug源。

我已经看到了大约20个谓词的代码,它们可以工作(或者至少可以工作得很好!)我使用的经验法则是,如果它看起来像狗的晚餐,我考虑重构。


不是谓词的数量,而是复杂性。只要你能用最少的努力理解代码的功能,我就可以理解。

除此之外,我不会更改为多个if,但会为谓词添加一个函数。特别是在几个地方使用相同数量的谓词时。


这个问题与长的条件列表不是那么多的可读性损失,而是测试性的损失。尤其是在处理糟糕的方法论证时,有时请求原谅而不是许可真的更容易(例如,请参阅这个问题的答案)。这样,您就可以保持代码的干净和可测试性,并修复调用者,或者让他们处理产生的异常。


但是,我认为没有任何规则:

  • 当你把它展示给别人时,他们会努力去理解它,这是否足够复杂?
  • 它需要覆盖多条线路吗?
  • 您是否有重复条件检查多个"if"子句?这将指向某个方法中所需的重构。
  • 如果上面的任何一个适用,我会重做它。


    哪条路更好?两者都不。两者的语义不同。

    我同意,虽然拆分使调试更容易,但条件断点也一样:)

    如果它是"和"或"或"的简单组合,超过3个测试,请重构它。


    这完全取决于需要做什么。但是,您可能希望研究的一件事情是switch语句,它可以减少某些算法的冗长性:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    switch (myVal)
    {
        case"isThis":
        case"isThat":
        case"something else":
            doThis();
            break;
        case"another":
        case"yet another":
        case"even another":
            doThat();
            break;
        case"another one":
        case"more more":
            doThisAgain();
            break;
    }

    在if-else语句中,这样做会非常冗长。一些代码将需要大量的if和else语句,一些将能够被压缩等等。只是永远不要为了代码源的漂亮而牺牲代码执行的质量。