if / else,好的设计

时间:2010-11-03 13:29:51

标签: c# if-statement

简化此功能是否可接受/良好风格:

bool TryDo(Class1 obj, SomeEnum type)
{
    if (obj.CanDo(type))
    {
        return Do(obj);
    }
    else
    {
        return false;
    }
}

为:

bool TryDo(Class1 obj, SomeEnum type)
{
    return obj.CanDo(type) && Do(obj);
}

第二个版本较短但可能不太直观。

20 个答案:

答案 0 :(得分:64)

我要编码的是:

return obj.CanDo(type) ? Do(obj) : false;

答案 1 :(得分:24)

带括号的版本:

bool TryDo(Class1 obj, SomeEnum type)
{
    if (obj.CanDo(type))
    {
        return Do(obj);
    }

    return false;
}

<击> 或者没有括号的版本(在回答评论中是关于它的争论很多):

bool TryDo(Class1 obj, SomeEnum type)
{
    /*
     * If you want use this syntax of
     * "if", this doing this on self
     * responsibility, and i don't want
     * get down votes for this syntax,
     * because if I remove this from my
     * answer, i get down votes because many
     * peoples think brackets i wrong.
     * See comments for more information.
     */
    if (obj.CanDo(type))
        return Do(obj);

    return false;
}

<击>

你的第一个代码示例更好,但我认为我的版本更好。

第二个版本的可读性不高,使代码难以维护,这很糟糕。

答案 2 :(得分:18)

else无用,而&&,无论多么明显,都不如纯文字那么可读。

我更喜欢以下内容:

bool TryDo(Class1 obj, SomeEnum type)
{
    if (obj.CanDo(type))
    {
        return Do(obj);
    }   
    return false;
}

答案 3 :(得分:13)

特别是名称类似于您选择的名称,即CanDoSomethingDoSomething,对于任何有能力的程序员来说,第二个代码的作用是绝对清晰:“ if并且只有当条件成立时,做一些事情并返回结果“。 “当且仅当”是短路&&运算符的核心含义。

第一个代码是复杂且不必要的长,而不提供比第二个代码更多的信息。

但总的来说,这两个条件可能不会形成如此亲密的关系(如CanDoDo),最好将它们逻辑分开,因为将它们放在同一条件中可能不会直觉。

很多人声称第一个版本“更加清晰”。我真的很想听听他们的论点。我想不出任何一个。

另一方面,这与密切相关(尽管不是相当相同)代码:

if (condition)
    return true;
else
    return false;

这应该始终转换为:

return condition;

无异常。对于掌握该语言能力的人来说,它更简洁,更具可读性。

答案 4 :(得分:12)

缩短版本隐藏了Do做某事的事实。看起来你只是在进行比较并返回结果,但实际上你正在进行比较并执行一个动作,并且代码具有这种“副作用”并不明显。

我认为问题的核心在于您返回评估结果和操作的返回代码。如果你以这种方式返回两个评估的结果,我就不会有问题

答案 5 :(得分:7)

另一种可能更具可读性的替代方法是使用条件运算符:

bool TryDo(Class1 obj, SomeEnum type) {
  return obj.CanDo(type) ? Do(obj) : false;
}

答案 6 :(得分:6)

第一版更容易阅读,更容易被误解,我认为这在现实代码中很重要。

答案 7 :(得分:6)

我不喜欢这种设计,也许不是因为显而易见的原因。困扰我的是。 return Do(obj); 对我而言,Do函数具有bool返回类型是没有意义的。这是否可以替代推动错误的财产? 很可能这个函数应该是void或返回一个复杂的对象。这种情况应该不会出现。 此外,如果一个bool现在以某种方式有意义,它将来很容易停止有意义。随着代码的更改,需要更多的因子来修复

答案 8 :(得分:5)

在这种情况下,我会选择第一个选项 - 很多更具可读性,而且代码的意图很多更清晰。

答案 9 :(得分:5)

两者都没有,因为当TryDo返回False时,你无法确定它是否是因为 '不能做'或'做错了'。

我完全明白你可以忽略结果,但它表达的方式暗示结果有意义。

如果结果毫无意义,

的意图会更清晰
void TryDo(Class1 obj, SomeEnum type)
{
    if (obj.CanDo(type))
        Do(obj);
    return;
}

如果结果确实有意义,那么应该有办法区分两个'假'回报。 I.E.什么'If(!TryDo(x))'意味着

编辑:换句话说,OP的代码是说'我不会游泳'和'我试图游泳和淹死'一样

答案 10 :(得分:4)

虽然对于一个称职的程序员来说,第二个代码肯定是清楚的,但在更一般的情况下,我会更清楚,更容易地阅读代码,就像任何其他代码一样“如果前提条件满足,请执行操作,否则会失败”风格。

这可以通过以下方式实现:

return obj.CanDo(type)? Do(obj) : false;

或者,

if(obj.CanDo(type)) return Do(obj);
return false;

我觉得这很优越,因为无论返回类型如何,都可以复制相同的样式。例如,

return (array.Length > 1)? array[0] : null;

或者,

return (curActivity != null)? curActivity.Operate() : 0;

同样的样式也可以扩展到没有返回值的情况:

if(curSelection != null)
    curSelection.DoSomething();

我的两分钱。

答案 11 :(得分:4)

我不喜欢第二个版本,因为我并不喜欢在条件表达式中利用子表达式求值的顺序。它在子表达式上放置了一个预期的排序,在我看来,它应该具有相同的优先级(即使它们没有)。

与此同时,我发现第一个版本有点臃肿,所以我选择了我认为非常易读的三元解决方案。

答案 12 :(得分:3)

IMO只有第二个功能没有副作用才行。但由于Do()有副作用,我会选择if。

我的指导原则是表达不应该有副作用。调用带副作用的函数时,请使用语句 如果函数返回失败代码,则此准则存在问题。在这种情况下,我接受将该错误代码分配给变量或直接返回它。但我不在复杂表达式中使用返回值。所以也许我应该说只有表达式中最外面的函数调用应该有副作用。

有关详细说明,请参阅Eric Lippert's Blog

答案 13 :(得分:3)

有些人提到的副作用问题是假的。没有人会对名为“Do”的方法产生副作用感到惊讶。

事实是,你正在调用两种方法。这两种方法都将bool作为返回值。您的第二个选择非常简洁明了。 (虽然我会摆脱外括号,你忘了一个结尾的分号。)

答案 14 :(得分:1)

我认为Class1 Type应该在给定SomeEnum值的情况下确定它是否可以。

我会决定是否可以处理输入以供其决定:

bool TryDo(Class1 obj, SomeEnum type)
{
    return obj.Do(type));    
}

答案 15 :(得分:1)

对我来说,我更喜欢第二种方法。当涉及简单的条件逻辑时,我的大多数返回bool的方法都以相同的方式缩短。

答案 16 :(得分:1)

我可能会因此而讨厌,但是:

if (obj.CanDo(type)) return Do(obj);
return false;

我不喜欢有一个衬垫的支撑。

答案 17 :(得分:1)

没有。第二个版本

return (obj.CanDo(type) && Do(obj))

依赖于&amp;&amp; amp;的短路行为。运算符是一种优化,而不是控制程序流的方法。在我看来,这与使用程序流的异常(几乎同样糟糕)略有不同。

我讨厌聪明的代码,这是一个理解和调试的婊子。该函数的目标是“如果我们可以这样做,那么执行它并返回结果,否则返回false”。原始代码非常清楚。

答案 18 :(得分:1)

永远不要那样做。保持简单直观。

答案 19 :(得分:1)

已经有好几个好的答案,但我想我会再展示一个(我考虑的)好的,可读的代码的例子。

bool TryDo(Class1 obj, SomeEnum type)
{
    bool result = false;

    if (obj.CanDo(type))
    {
        result = Do(obj);
    }

    return result;
}

根据品味,在if语句的主体周围保留或移除花括号。

我喜欢这种方法,因为它说明结果是false,除非发生其他事情,我认为它更清楚地表明Do()正在做某事并返回一个布尔值,{{1}用作返回值。