想象以下代码:
void DoThis()
{
if (!isValid) return;
DoThat();
}
void DoThat() {
Console.WriteLine("DoThat()");
}
在void方法内使用return可以吗?它有性能损失吗?或者编写这样的代码会更好:
void DoThis()
{
if (isValid)
{
DoThat();
}
}
想象以下代码:
void DoThis()
{
if (!isValid) return;
DoThat();
}
void DoThat() {
Console.WriteLine("DoThat()");
}
在void方法内使用return可以吗?它有性能损失吗?或者编写这样的代码会更好:
void DoThis()
{
if (isValid)
{
DoThat();
}
}
Answers:
void方法中的返回值还不错,这是反转if
语句以减少嵌套的一种常见做法。
而且,减少方法上的嵌套可以提高代码的可读性和可维护性。
实际上,如果您有一个没有任何return语句的void方法,则编译器将始终在其末尾生成ret指令。
使用防护措施的另一个重要原因(与嵌套代码相对):如果另一个程序员向您的函数中添加了代码,则它们在更安全的环境中工作。
考虑:
void MyFunc(object obj)
{
if (obj != null)
{
obj.DoSomething();
}
}
与:
void MyFunc(object obj)
{
if (obj == null)
return;
obj.DoSomething();
}
现在,假设另一个程序员添加了这一行:obj.DoSomethingElse();
void MyFunc(object obj)
{
if (obj != null)
{
obj.DoSomething();
}
obj.DoSomethingElse();
}
void MyFunc(object obj)
{
if (obj == null)
return;
obj.DoSomething();
obj.DoSomethingElse();
}
显然,这是一种简单的情况,但是程序员在第一个(嵌套代码)实例中向程序添加了崩溃。在第二个示例(带防护的早期退出)中,一旦您越过防护,您的代码就可以避免意外使用空引用。
当然,出色的程序员不会犯此类错误(通常)。但是预防胜于治疗-我们可以以完全消除这种潜在错误源的方式编写代码。嵌套会增加复杂性,因此最佳实践建议重构代码以减少嵌套。
不好的做法???没门。实际上,总是最好通过在验证失败时从方法中最早返回来处理验证。否则,将导致大量的ifs和else嵌套。尽早终止可提高代码的可读性。
还要检查对类似问题的回答:我应该使用return / continue语句代替if-else吗?
第一个示例是使用保护语句。从维基百科:
在计算机编程中,guard是一个布尔表达式,如果要在相关分支中继续执行程序,则必须将其评估为true。
我认为在方法的顶部放置一堆警卫是一种完全可以理解的编程方法。基本上是说“如果其中任何一个为真,则不要执行此方法”。
因此,一般来说,它是这样的:
void DoThis()
{
if (guard1) return;
if (guard2) return;
...
if (guardN) return;
DoThat();
}
我认为那更具可读性:
void DoThis()
{
if (guard1 && guard2 && guard3)
{
DoThat();
}
}
没有性能损失,但是第二段代码更具可读性,因此更易于维护。
完全可以,没有“性能损失”,但是永远不要写没有括号的“ if”语句。
总是
if( foo ){
return;
}
它更具可读性;并且您永远不会意外地认为代码的某些部分不在该语句之内。
{
。这使您{
与您}
在同一列中对齐,这极大地提高了可读性(更容易找到对应的打开/关闭括号)。
if
语句需要右括号很容易,因此让if
语句控制单个语句将是安全的。用来将开括号推回该行if
可以在每个多语句中节省一行垂直空间if
,但是将需要使用其他不必要的闭括号行。
我将不同意所有对此的年轻胡扯。
由于将近四十年前已故的Edsger W. Dijkstra很清楚地阐明了原因,所以在方法中间使用void或其他方法返回是非常不好的做法,始于著名的“ GOTO声明被认为有害”。 ”,并继续进行Dahl,Dijkstra和Hoare撰写的“结构化程序设计”。
基本规则是,每个控制结构和每个模块都应具有一个入口和一个出口。模块中间的显式返回会破坏该规则,并使推理程序状态变得更加困难,这反过来使得很难判断程序是否正确(这是更强大的属性)。而不是“是否似乎有效”)。
“ GOTO声明被认为有害”和“结构化编程”开始了1970年代的“结构化编程”革命。这两个部分是我们今天拥有if-then-else,while-do和其他显式控制构造的原因,以及为什么使用高阶语言的GOTO语句位于“濒危物种”列表中的原因。(我个人认为它们需要列入“绝种”列表中。)
值得注意的是,消息流调制器(Message Flow Modulator)是第一次尝试通过验收测试的第一款军事软件,没有偏差,弃权或“是的,但是”的说法,是用一种甚至没有GOTO语句。
还值得一提的是,尼克劳斯·沃思(Nicklaus Wirth)更改了Oberon-07(Oberon编程语言的最新版本)中RETURN语句的语义,使其成为类型化过程(即函数)声明的结尾部分,而不是函数主体中的可执行语句。他的变化解释说,他这样做是正是因为以前的形式WAS违反了结构化编程的一个退出的原则。
使用防护罩时,请确保遵循某些准则,以免混淆读者。
例
// guards point you to the core intent
void Remove(RayCastResult rayHit){
if(rayHit== RayCastResult.Empty)
return
;
rayHit.Collider.Parent.Remove();
}
// no guards needed: function split into multiple cases
int WonOrLostMoney(int flaw)=>
flaw==0 ? 100 :
flaw<10 ? 30 :
flaw<20 ? 0 :
-20
;