关于c#:在一个方法中使用多一个RETURN语句是不错的做法?

Is it good practice use more that one RETURN statement in a method?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Why is it good practice to return at the end of a method

我想知道在一个方法中使用多个返回语句是否被认为是一个好的实践以及为什么。如果没有,我想知道您将如何以不同的方式重写代码。

1
2
3
4
5
6
7
8
public string GetNominativeById(int? candidateId)
        {
            if (candidateId.HasValue)
                return repepositoryCandidate.GetById(candidateId.Value).Nominative;
             else
                return string.Empty;
            }
        }

一回

1
2
3
4
5
6
7
8
9
10
11
 public string GetNominativeById(int? candidateId)
    {
        string result;
        if (candidateId.HasValue)
            result =  repepositoryCandidate.GetById(candidateId.Value).Nominative;
         else
            result =  string.Empty;

        return result;
        }
    }


你实际上不需要else

1
2
3
4
5
6
7
string GetNominativeById(int? candidateId)
{
    if (!candidateId.HasValue)  
        return string.Empty;

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

考虑这个反箭头模式:

1
2
3
4
5
6
7
8
9
10
if (condition1)
{
    if (condition2)
    {
        if (condition3)
        {
            // code lines
        }
    }
}

立即返回的方法将使代码更具可读性:

1
2
3
4
5
if (!condition1) return;
if (!condition2) return;
if (!condition3) return;

// code lines


不,在一个方法中有多个出口点被认为是不好的做法。如果只有一个出口,遵循代码就更容易了。

但是,当该方法与示例中的方法一样小时,不管怎样,遵循代码并不困难,因此拥有多个出口点并不是真正的问题。如果它使代码更简单,您可以很好地使用多个return语句。


尽管为了便于阅读,您应该尽量只使用一个返回语句,但有几个模式涉及多个返回语句。一个例子是guard子句。

guard子句示例:

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

有些样式指南会让我们用一个返回值来编写这个,如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
  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语句,当您可能希望从每个情况返回时:

1
2
3
4
5
6
7
8
9
switch(foo)
{
   case"A":
     return"Foo";
   case"B":
     return"Bar";
   default:
     throw new NotSupportedException();
}

我会把你的代码改写为:

1
2
3
4
5
6
        public string GetNominativeById(int? candidateId)
        {
            return candidateId.HasValue
                ? repepositoryCandidate.GetById(candidateId.Value).Nominative;
                : string.Empty;
        }

最后,请记住您(和其他开发人员)将多次阅读您的代码,因此请确保代码可读且明显。


看看下面关于维基百科的文章。您要问的是,是否应该从结构化编程中遵循SESE(单入口、单出口)原则。


有更多的RETURN语句没有什么问题,有时它实际上帮助您缩小代码并保存一些不必要的变量赋值,如Cuong le指出的那样。D


这一切都取决于

  • 与其他开发人员一起使用的编码标准
  • 以及实际的代码可读性(所以个人对代码的感知)

一般来说,当if/else变得太多时,我使用return

所以不用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if(...)
{
    if(...)
    {
        if(...)
        {
        }
    }
    else if(...)
    {
    }
     ..
    else
    {
    }
}

使用return

1
2
3
4
5
if(!...)
   return;

if(!...)
   return;


结构化编程规则之一规定每个方法都应该有一个入口和出口点。只有一个出口点(本例中的return语句)意味着任何清理(如调用close或dispose)只需要执行一次。多个退出点对小方法的影响很小,但随着方法复杂性的增加而增加,在这种情况下很容易错过案例,或者作为重构或修改的代码。


习惯于在方法的末尾添加return,因此必须关闭任何活动对象(如果有)。

1
2
3
4
5
6
7
8
9
10
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语句中有一些情况是您的多个代码块。


是的,如果有必要,那么为什么不使用几个返回语句呢?演出不会有问题。

要重写此代码:

1
2
3
4
5
6
7
public string GetNominativeById(int? candidateId)
{
    if (candidateId.HasValue)
          return repepositoryCandidate.GetById(candidateId.Value).Nominative;

    return string.empty;
}

或使用"三元运算符"。

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

实际上,在一个方法中不能使用多个RETURN语句,就像您在代码中所做的那样,您使用了一个if-else语句,因此无论如何只执行一个语句。我觉得你的代码不错。


为什么不?但你不需要别的。

1
2
3
4
5
6
public string GetNominativeById(int? candidateId)
        {
            if (candidateId.HasValue)
                return repepositoryCandidate.GetById(candidateId.Value).Nominative;
            return string.Empty;
        }