0

我应该在返回之前保存 switch 语句的结果吗?或者当我得到它时我应该返回开关中的值吗?有没有一种方法比另一种更好的风格?

使用临时变量:

      public double xMax {
      get {
           double val = 0.00f;
           switch(x_option) {
                case 0:
                     val = priMax;
                     break;
                case 1:
                     val = rfMax;
                     break;
                case 2:
                     val = pwMax;
                     break;
           }

           return val;
      }
 }

带有返回语句:

 public double xMax {
      get {
           double val = 0.00f;
           switch(x_option) {
                case 0:
                     return priMax;
                case 1:
                     return rfMax;
                case 2:
                     return pwMax;
           }
      }
 }

是否存在性能差异和/或清理?

4

5 回答 5

5

我个人更喜欢第二种形式。它立即清楚地表明,一旦您到达 return 声明,您就完成了。使用额外的变量版本,您必须查看其余代码以查看是否会发生其他任何事情。

围绕单点返回的教条在 C 语言中是有意义的,在 C 语言中,您希望确保完成所有手动清理等工作 - 但在一个无论如何都必须考虑异常可能性以及垃圾收集器的世界中处理大部分清理工作,try/finally处理其余部分,我发现在很多情况下,坚持使用单个退出点会使代码显着难以阅读 - 特别是在您可以在方法开始时确定结果的情况下(例如“如果输入字符串为空,则结果始终为 0 - 所以只需将其返回)。

编辑:为了清楚起见,在您的情况下,我认为这没有太大区别。但这是一种单点返回变得混乱的代码:

 public int DoSomething(string input1, string input2)
 {
     // First simple case
     if (input1 == null || input2 == null)
     {
         return -1;
     }

     // Second simple case
     int totalLength = input1.Length + input2.Length;
     if (totalLength < 10)
     {
         return totalLength;
     }

     // Imagine lots of lines here, using input1, input2 and totalLength
     // ...
     return someComplicatedResult;
 }

使用单点返回,这将变为:

 public int DoSomething(string input1, string input2)
 {
     int ret;

     // First simple case
     if (input1 == null || input2 == null)
     {

         ret = -1;
     }
     else
     {
         // Second simple case
         int totalLength = input1.Length + input2.Length;
         if (totalLength < 10)
         {
             ret = totalLength;
         }
         else
         {
             // Imagine lots of lines here, using input1, input2 and totalLength
             // ...
             ret = someComplicatedResult;
         }
     }
     return ret;
 }

肯定宁愿阅读第一种形式而不是第二种形式:

  • 更多的嵌套通常会使代码更难理解。很难记住你要去哪里
  • 在第一种形式中,您可以清楚地告诉 - 无需阅读更多代码 - 如果您了解基本情况,您就完成了。复杂的代码之后不会有任何副作用;我们只是要回来。在第二个代码中,您必须在精神上跳过“其他”块才能弄清楚发生了什么。您正在查看更多代码以找出路径。
于 2012-09-20T20:25:22.417 回答
2

嗯,最重要的是不要混合它们。

第一种形式的一个动机是它有一个从 getter 退出的点。如果代码比示例中的更复杂,那可能很有用,但在像这样的简单示例中,这并不重要。

只要代码像示例中那样简单,第二种形式的简单性就是一个很好的论据。


您的第二个示例没有像现在这样编译,因为代码可能会到达属性的末尾而不返回任何内容。在第一种情况下,您可以在切换之前将变量设置为默认值,对于第二种情况,您应该在切换中使用默认选项,并且您根本不需要该变量:

public double xMax {
  get {
    switch(x_option) {
      case 0:
        return priMax;
      case 1:
        return rfMax;
      case 2:
        return pwMax;
      default:
        return 0d;
    }
  }
}
于 2012-09-20T20:52:18.530 回答
1

这是一个品味问题,但我更喜欢在可能的情况下获得单点退货。更容易调试,让你在使用代码契约时更清楚地检查 pre 和 post。

于 2012-09-20T20:23:44.867 回答
0

这个问题是两代人的。但我会回答这个问题,因为这个问题曾经也困扰着我。


这是您正在查看的内容:语法 A语法 B

你应该看什么:整个代码中的语法一致性。

选择一种风格并坚持下去。这可以由个人选择、团队选择、老板选择等决定。在遇到瓶颈之前担心性能是本末倒置。


作为代码和复杂性积累的一般后果,如果您面临 switch 语句,那么有人在某处编写了错误的代码并试图在一个代码的一个毛线球中处理很多事情。

恰当的例子:一个返回 JSON 的 API 调用,它在一个数组中发回 5 个不同的值,您需要弄清楚如何处理它或根据需要选择哪些数据。


大多数时候,只要有多个返回或 if 的可能性,您就应该将代码分成小块。

以 Jon Skeet 的代码为例:

public int DoSomething(string input1, string input2)
 {
     int ret;

     // First simple case
     if (input1 == null || input2 == null)
     {

         ret = -1;
     }
     else
     {
         // Second simple case
         int totalLength = input1.Length + input2.Length;
         if (totalLength < 10)
         {
             ret = totalLength;
         }
         else
         {
             // Imagine lots of lines here, using input1, input2 and totalLength
             // ...
             ret = someComplicatedResult;
         }
     }
     return ret;
 }


让我们先看看能否让代码更具可读性。

private int someComplicatedTask(string input1, string input2){
    // Second simple case
    int ret = 0;
    int totalLength = input1.Length + input2.Length;
    if (totalLength < 10)
    {
        ret = totalLength;
    }
    else
    {
       // Imagine lots of lines here, using input1, input2 and totalLength
       // ...
       ret = someComplicatedResult;
    }
    return ret;
}

public int DoSomething(string input1, string input2)
 {
     return input1 == null || input2 == null ? -1 : someComplecatedTask(...);
 }

这应该让您想知道,“当输入可能为空时,您为什么要调用 DoSomething?”。

请注意问题尚未解决。我所做的只是让代码看起来更好。

以下是我在 if 条件下的处理方式:

空输入的条件将移出到清理功能。或者只有当输入不为空时才会调用。

...
if(input1 != null && input2 != null){
    output = DoSomething(input1, input2);
}
...

public int DoSomething(string input1, string input2)
{
    int len = input1.Length + input2.Length;
    return len < 10 ? len : someComplecatedTask(input1, input2);
}

private int someComplicatedTask(string input1, string input2){
    // Imagine lots of lines here, using input1, input2
    // ...
    return someComplicatedResult;
}

因此,代码现在看起来更易于管理。代码只有两条路可以走,一切都很好。


现在让我们看看您的第一个代码片段。

public double xMax {
      get {
           double val = 0.00f;
           switch(x_option) {
                case 0:
                     val = priMax;
                     break;
                case 1:
                     val = rfMax;
                     break;
                case 2:
                     val = pwMax;
                     break;
           }

           return val;
      }
 }

在我看来,这很糟糕,原因有两个:
1. 将来某个时候,x_option 会获得另一个值,您将在每次 get {} 下寻找适当的更改。
2. 获取 {} 应该是直截了当的。Set {} 应包含设置适当值的条件。

所以代码应该看起来像这样:

public double xMax {
      set {
           double val = 0.00f;
           switch(value) {
                case 0:
                     val = priMax;
                     break;
                case 1:
                     val = rfMax;
                     break;
                case 2:
                     val = pwMax;
                     break;
           }
           xmax = value * val; // say // This makes break better in switch.
      }
      get { return xmax; }
 }

因为,在你的情况下,你可以做更多的(所有情况下通用的)操作,那么这比返回要好。这个例子相对于 get one 更好,因为在设置时你不知道值,所以你需要一个决策树。

但是在获取时,您的对象确切地知道它包含什么,并兴高采烈地返回所询问的内容。

现在,您的第二个代码示例根本没有意义。决定返回什么不是对象的职责。它应该返回它所拥有的东西。

在设置时,无论如何你都不应该强行返回。

我希望这能消除一些疑虑并提出更多问题,因为还有很多东西要学。

于 2015-08-23T06:21:11.613 回答
-1

在我在华沙军事科技大学的第一堂编程课上,Eng 博士。Zbigniew Wesołowski 表示,该函数只能有一个返回点。这是对 ANSI-C 编程的介绍,但他也告诉我们,我们永远不应该忘记这一点,因为这是一个普遍的规则,无论我们必须使用哪种语言进行开发。更重要的是,就像一个暴君一样,他表示如果他尝试使用 goto 语句、在函数中间返回或在 for 循环中修改迭代器,他永远不会通过考试。

中途返回,还是不返回,是个老年难题。一些人声称它使代码更清晰,但它并不优雅,应该避免。根据我的经验,我注意到,java 代码中最常出现多个返回,而 c、c++ 和 c# 程序员则避免这种情况。这不是规则,只是观察。

另一个观察结果是 java 语言鼓励紧凑的语法。Java IDE(例如eclipse)通常将默认格式化程序设置为将左大括号放在同一行(只是一个简单的例子)。多个返回与该方法一致,允许进一步压缩代码。

相反的 Visual Studio 将新行上的左大括号作为唯一字符。它鼓励清晰、粗体的语法、长文件、许多空白或单个字符行。我不知道哪个更好,如果有的话。

基本上我在大学和家里的课堂上编写 C#。然后我更喜欢带有空行的长文件。

在我的公司,我编写 java 代码,然后我更喜欢更紧凑的风格,我已经习惯了。在公司中,我们使用 checkstyle 通过统一的样式来保持良好的代码质量。在公司存在多年的情况下,checkstyle 一直存在规则,根本不允许多次退货。

我在 stackoverflow 上看到过一篇帖子,有人发布说它会对性能产生影响。在一个答案中,他得到了一个简单的基准检查结果。事实上并没有太大的区别。

在我的编码实践中,我宁愿避免多次返回。但你的整体决定将取决于你的个人品味、经验、习惯、信仰,也许还有质量要求。

于 2012-09-20T20:30:22.660 回答