C# 倒置;如果;减少嵌套的声明

C# 倒置;如果;减少嵌套的声明,c#,resharper,C#,Resharper,当我运行代码时,例如: if (some condition) { Some code... } double getPayAmount() { double result; if (_isDead) result = deadAmount(); else { if (_isSeparated) result = separatedAmount(); else {

当我运行代码时,例如:

    if (some condition)
    {
        Some code...            
    }
double getPayAmount() {
    double result;
    if (_isDead) result = deadAmount();
    else {
        if (_isSeparated) result = separatedAmount();
        else {
            if (_isRetired) result = retiredAmount();
            else result = normalPayAmount();
        };
    }
     return result;
};
ReSharper给了我上述警告(反转“if”语句以减少嵌套),并建议进行以下更正:

   if (!some condition) return;
   Some code...

我想知道为什么这样更好。我一直认为,在一个方法的中间使用“返回”有点像“Goto”。

< P>这是很有争议的。在提前返回的问题上没有“程序员之间的协议”。据我所知,这总是主观的

可以进行性能论证,因为最好编写条件,使其通常为真;也可以说它更清晰。另一方面,它确实创建嵌套测试


我不认为你能得到这个问题的最终答案。

这是一个意见问题

我通常的方法是避免单行IFS,并且在方法的中间返回。< /P>


你不希望在你的方法中到处都出现这样的线条,但有一点值得一提,那就是在你的方法顶部检查一系列假设,并且只有在它们都通过的情况下才进行实际工作。

这是一个有点宗教色彩的论点,但我同意ReSharper的观点,即你应该选择较少的嵌套。我相信这比从一个函数获得多个返回路径的负面影响更大

减少嵌套的关键原因是提高代码的可读性和可维护性。请记住,许多其他开发人员将来需要阅读您的代码,缩进较少的代码通常更易于阅读

先决条件是一个很好的例子,说明在函数开始时可以提前返回。为什么函数其余部分的可读性会受到前提条件检查的影响

至于从一个方法返回多次的缺点,调试器现在非常强大,而且很容易找到特定函数返回的确切位置和时间

在一个函数中有多个返回不会影响维护程序员的工作


糟糕的代码可读性会影响你的阅读能力。

我认为这取决于你喜欢什么,正如前面提到的,目前还没有达成一致意见。
为了减少烦恼,您可以将此类警告减少为“提示”

这当然是主观的,但我认为它在两点上有很大的改进:

  • 现在很明显,如果
    条件
    保持不变,您的函数将无事可做
  • 它可以降低筑巢的水平。嵌套对可读性的伤害比你想象的要大

保护条款或先决条件(如您可能看到的)检查是否满足某个条件,然后中断程序流程。它们非常适合您只对
if
语句的一个结果感兴趣的地方。与其说:

if (something) {
    // a lot of indented code
}
您可以反转条件,如果反转条件已满足,则中断

if (!something) return false; // or another value to show your other code the function did not execute

// all the code from before, save a lot of tabs
return
远不如
goto
脏。它允许您传递一个值,以显示函数无法运行的其余代码

您将看到在嵌套条件下可以应用此功能的最佳示例:

if (something) {
    do-something();
    if (something-else) {
        do-another-thing();
    } else {
        do-something-else();
    }
}
vs:

你会发现很少有人认为第一个更干净,但当然,这完全是主观的。一些程序员喜欢通过缩进来了解某些东西在什么条件下运行,而我更愿意让方法流保持线性


我一刻也不会说precons会改变你的生活或让你上床,但你可能会发现你的代码只是简单一点而已。

我的想法是,“在函数中间”的返回不应该如此“主观”。 原因很简单,以下面的代码为例:

function do_something( data ){ if (!is_valid_data( data )) return false; do_something_that_take_an_hour( data ); istance = new object_with_very_painful_constructor( data ); if ( istance is not valid ) { error_message( ); return ; } connect_to_database ( ); get_some_other_data( ); return; } 函数做某事(数据){ 如果(!是有效的数据(数据)) 返回false; 做一些花费一小时的事情(数据); istance=新对象,具有非常痛苦的构造函数(数据); 如果(istance无效){ 错误消息(); 返回; } 将_连接到_数据库(); 获取一些其他数据(); 返回; } 也许第一次“返回”不是那么直观,但这真的节省了。
关于清洁守则有太多的“想法”,只需要更多的练习就失去了“主观”的坏想法。如果能让代码的意图更清楚,那么最好立即返回。例如:

    if (some condition)
    {
        Some code...            
    }
double getPayAmount() {
    double result;
    if (_isDead) result = deadAmount();
    else {
        if (_isSeparated) result = separatedAmount();
        else {
            if (_isRetired) result = retiredAmount();
            else result = normalPayAmount();
        };
    }
     return result;
};
在这种情况下,如果
\u isDead
为真,我们可以立即退出该方法。这样做可能会更好:

double getPayAmount() {
    if (_isDead)      return deadAmount();
    if (_isSeparated) return separatedAmount();
    if (_isRetired)   return retiredAmount();

    return normalPayAmount();
};   

我从计算机中选择了这个代码。这种特定的重构被称为:用保护子句替换嵌套的条件语句。

在语言支持异常之前,只在函数结束时返回的想法就已经出现了。它使程序能够依赖于能够将清理代码放在方法的末尾,然后确保它将被调用,并且其他程序员不会在方法中隐藏导致跳过清理代码的返回。跳过的清理代码可能导致内存或资源泄漏

但是,在支持异常的语言中,它不提供此类保证。在支持异常的语言中,任何语句或表达式的执行都可能导致导致方法结束的控制流。这意味着必须通过使用finally或关键字来完成清理


无论如何,我想说的是,很多人引用了“方法末尾的唯一返回”准则,却不理解为什么这样做是一件好事,减少嵌套以提高可读性可能是更好的目标。

多个返回点在C中是一个问题(在较小程度上是C++)因为它们迫使您在每个返回点之前复制清理代码。与ga
using System;

public class Test {
    public static void Main(string[] args) {
        if (args.Length != 0 && (args.Length+2)/3 != 5) 
        {
            Console.WriteLine("hey!!!");
        }
    }
}
 bool PerformDefaultOperation()
 {
      bool succeeded = false;

      DataStructure defaultParameters;
      if ((defaultParameters = this.GetApplicationDefaults()) != null)
      {
           succeeded = this.DoSomething(defaultParameters);
      }

      return succeeded;
 }
public void myfunction(double exampleParam){
    if(exampleParam > 0){
        //Body will *not* be executed if Double.IsNan(exampleParam)
    }
}
public void myfunction(double exampleParam){
    if(exampleParam <= 0)
        return;
    //Body *will* be executed if Double.IsNan(exampleParam)
}