在一个方法中使用多个RETURN语句是一种好的编程实践吗?

19

可能是重复问题:
为什么在方法的结尾处返回是良好的编程实践

我想知道在一个方法中是否可以考虑使用多个 RETURN 语句,以及为什么这样做可以被认为是良好的实践。 如果不行,我希望知道你将如何以不同的方式重写代码。

public string GetNominativeById(int? candidateId)
        {
            if (candidateId.HasValue)
                return repepositoryCandidate.GetById(candidateId.Value).Nominative;
             else
                return string.Empty;
            }
        }

只需一个RETURN

 public string GetNominativeById(int? candidateId)
    {
        string result;
        if (candidateId.HasValue)
            result =  repepositoryCandidate.GetById(candidateId.Value).Nominative;
         else
            result =  string.Empty;

        return result;
        }
    }

“如果被认为是良好的实践”,你怎么看?返回值越多越好吗? - zerkms
第二个例子应该会产生一个关于无法到达的代码的警告,这也回答了你的问题。 - slugster
1
请查看常见问题解答。这个问题实际上没有一个确定的答案,完全是一个观点问题,并且双方都有狂热者。 - verdesmarald
另一个重复的问题:一个函数应该只有一个返回语句吗? - slugster
11个回答

31

实际上你不需要else

string GetNominativeById(int? candidateId)
{
    if (!candidateId.HasValue)  
        return string.Empty;

    return repepositoryCandidate.GetById(candidateId.Value).Nominative;
}

考虑这种反箭头模式

if (condition1)
{
    if (condition2)
    {
        if (condition3)
        {
            // code lines
        }
    }
}

立即返回的方式将使您的代码更易读:

if (!condition1) return;
if (!condition2) return;
if (!condition3) return;

// code lines

2
有趣的观点,非常感谢! - GibboK
如果(condition1 && condition2 && condition3) { //代码行 },这样会更好。 - Elo

15

不,一个方法中有多个退出点被认为是不太好的实践。如果有一个单一的退出点,那么代码更容易理解。

然而,在本例中这个方法非常简短,所以即使存在多个退出点,代码也不难跟踪。如果使用多个return语句让代码更简单,请放心使用。


感谢Guffa的评论! - GibboK
1
如果只有一个出口点,跟踪代码会更容易。在许多情况下是这样,但我不同意一般情况下的这种说法。其他答案包括几个例子,这些代码使用多个返回语句更容易阅读。 - BJ Myers
第二个例子中,“一个”退出点实际上有多个退出点。如果repepositoryCandidate为null或GetById()返回null或抛出异常,则该简单方法具有更多的退出点。按照多个退出点是“不好”的逻辑,那么您将不得不捕获/忽略所有异常以保持单个退出点将是“好”的做法。 - John
1
我认为并没有像你的回答所表现出来的那样达成共识。我完全不同意这个作为一般原则的观点,我看到人们搞砸了本可以更简单的代码,只是为了有一个单一的退出点。例如,如果你知道你可以在循环内部提前退出,那么如何比设置标志、跳出循环、然后重新检查标志或稍后返回标志更容易阅读呢?直接在循环内使用已知结果的返回语句不就好了吗? - Mike Marynowski
请查看这里的接受答案:https://softwareengineering.stackexchange.com/questions/118703/where-did-the-notion-of-one-return-only-come-from我不知道这个在现代语言中是如何成为常见的“惯例”的。 - Mike Marynowski

10

尽管出于可读性考虑,您应该努力只有一个返回语句,但有几种涉及多个返回语句的模式。其中一种例子是Guard Clause

守卫子句的示例:

  public Foo merge (Foo a, Foo b) {
    if (a == null) return b;
    if (b == null) return a;
    // complicated merge code goes here.
  }

一些编码规范建议我们使用单个换行符来书写,如下所示:

  public Foo merge (Foo a, Foo b) {
    Foo result;
    if (a != null) {
      if (b != null) {
        // complicated merge code goes here.
      } else {
        result = a;
      }
    } else {
      result = b;
    }
    return result;
  }

另一个情况是在 switch 语句中,当你可能想要从每个 case 中返回时:

switch(foo)
{
   case "A":
     return "Foo";
   case "B":
     return "Bar";
   default:
     throw new NotSupportedException();
}

我会将您的代码重写为:

        public string GetNominativeById(int? candidateId)
        {
            return candidateId.HasValue 
                ? repepositoryCandidate.GetById(candidateId.Value).Nominative;
                : string.Empty;
        }

最终,要记得你(以及其他开发者)将会反复阅读你的代码,所以请确保它易于阅读和理解。


1
有趣的方法,非常感谢! - GibboK

6
请看一下维基百科上关于结构化编程的文章,你所问的是是否应该遵循结构化编程中的SESE(单入口、单出口)原则。

感谢指出这篇文章! - GibboK

3

结构化编程的规则之一是每个方法都应该有一个单一的进入点和出口点。只有一个出口点(在这种情况下是return语句)意味着任何清理工作,如调用Close或Dispose,只需要执行一次。具有多个出口点的影响对于小型方法来说是微不足道的,但随着方法复杂性的增加而增加,在这种情况下可能很容易错过某些情况,或者在代码被重构或修改时。


3

有更多的返回语句并没有什么问题,有时它实际上可以帮助您缩小代码,并避免一些不必要的变量赋值,就像Cuong Le指出的那样。 :D


2

养成在方法末尾添加return的习惯,这样你就不必关闭任何活动对象(如果你有的话)。

public string GetNominativeById(int? candidateId)
{
    string _returnValue = string.Empty;
    if (candidateId.HasValue)
        _returnValue repepositoryCandidate.GetById(candidateId.Value).Nominative;
     else
        _returnValue =  string.Empty;

    return _returnValue;
}

旁注:三元运算符并不是解决这个问题的真正答案(我认为),因为在你的IF语句中可能有多个代码块。


2
“所以你必须关闭任何活动对象” --- 这句话的意思是什么? - zerkms

2

所有这些都取决于你与其他开发人员使用的编码标准和实际代码可读性(因此是对代码的个人感知)。

通常情况下,当if/else语句过多时,我会使用return语句代替。

因此,不要使用:

if(...)
{
    if(...)
    {
        if(...)
        {
        }
    }
    else if(...)
    {
    }
     ..
    else
    {
    }
}

使用return关键字:

if(!...)
   return;

if(!...)
   return;

我刚刚更改了一些旧代码。if / else 嵌套了几层,我不想再添加另一层,但也不想重写/重构大量的代码。我随后遇到这个问题,检查看看现在是否有多个出口是一个好的实践。此帖子中有一些很好的观点。 - Steve

1

如果有必要,为什么不使用多个返回语句呢?这样不会影响性能。

重新编写此代码:

public string GetNominativeById(int? candidateId)
{
    if (candidateId.HasValue)
          return repepositoryCandidate.GetById(candidateId.Value).Nominative;

    return string.empty;
}

或者使用“三元运算符”。

public string GetNominativeById(int? candidateId)
{
     return candidateId.HasValue ? repepositoryCandidate.GetById(candidateId.Value).Nominative : string.Empty;  
}

1

在一个方法中实际上不能使用多个返回语句,你在你的代码中使用了if else语句,所以只有一个会被执行。你的代码看起来很好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接