题
我经常以两种格式编写这种功能,我想知道一种格式是否优于另一种格式,以及为什么。
public void SomeFunction(bool someCondition)
{
if (someCondition)
{
// Do Something
}
}
或者
public void SomeFunction(bool someCondition)
{
if (!someCondition)
return;
// Do Something
}
我通常会与第一个编码,因为这是我的大脑在编码时的工作方式,尽管我认为我更喜欢第二个,因为它会立即处理任何错误处理,而且我发现阅读更容易阅读
解决方案
我更喜欢第二种样式。首先将无效的案例弄清楚,要么简单地退出或适当地提高异常,在其中放置一条空白,然后添加该方法的“真实”主体。我发现阅读更容易。
其他提示
绝对是后者。前者现在看起来还不错,但是当您获得更复杂的代码时,我无法想象有人会认为这一点:
public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
int retval = SUCCESS;
if (someCondition)
{
if (name != null && name != "")
{
if (value != 0)
{
if (perms.allow(name)
{
// Do Something
}
else
{
reval = PERM_DENY;
}
}
else
{
retval = BAD_VALUE;
}
}
else
{
retval = BAD_NAME;
}
}
else
{
retval = BAD_COND;
}
return retval;
}
比可读性比
public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
if (!someCondition)
return BAD_COND;
if (name == null || name == "")
return BAD_NAME;
if (value == 0)
return BAD_VALUE;
if (!perms.allow(name))
return PERM_DENY;
// Do something
return SUCCESS;
}
我完全承认,我从不了解单个出口点的优势。
这取决于 - 总的来说,我不会竭尽全力尝试移动一堆代码以尽早爆发功能 - 编译器通常会为我照顾。话虽如此,如果顶部有一些基本参数我需要并且不能继续,否则我会尽早突破。同样,如果条件会产生巨大 if
功能障碍我也将提前突破。
话虽如此,如果一个函数在被调用时需要一些数据,我通常会抛出异常(见示例),而不是返回。
public int myFunction(string parameterOne, string parameterTwo) {
// Can't work without a value
if (string.IsNullOrEmpty(parameterOne)) {
throw new ArgumentNullException("parameterOne");
}
if (string.IsNullOrEmpty(parameterTwo)) {
throw new ArgumentNullException("parameterTwo");
}
// ...
// Do some work
// ...
return value;
}
我更喜欢提早回报。
如果您有一个入口点和一个出口点,那么您始终必须一直跟踪整个脑海中的整个代码(直到出口点)必须对其进行跟踪,直到存在为止)。您没有做任何分支机构决定最终结果的信息。这很难遵循。
有一个条目并存在多个条目,您在获得结果时返回,并且不要一直跟踪它,以发现没有人对它做任何其他事情(因为自返回以来,没有其他任何事情)。这就像让主体分为更多步骤一样,每个步骤都具有返回结果的可能性,或者让下一步尝试运气。
在C编程中,您必须手动清理,一分钟的回报有很多话要说。即使现在不需要清理某些东西,也可能会编辑您的功能,分配某些内容并需要在返回之前将其清理。如果发生这种情况,那将是一场噩梦工作,浏览所有返回声明。
在C ++编程中,您有攻击器甚至范围外警卫。所有这些都需要在这里以确保代码首先是例外安全,因此,代码可以很好地防止提早出口,因此这样做没有逻辑下跌,纯粹是样式问题。
我对Java的了解还不够多,是否会被调用“最终”块代码,以及最终化器是否可以处理需要确保发生某些事情的情况。
C#我当然无法回答。
D语言为您提供了适当的内置示波器外警卫,因此已为早期出口做好准备,因此不应出现其他问题。
当然,函数首先不应该很长,如果您有一个巨大的开关语句,您的代码也可能会受到严格的考虑。
赢得胜利。他们看起来很丑陋,但比大丑陋得多 if
包装器,特别是如果有多种条件进行检查。
我两者都使用。
如果 DoSomething
是3-5行代码,然后使用第一个格式化方法看起来很漂亮。
但是,如果它的行比这更多,那么我更喜欢第二种格式。我不喜欢开口和关闭括号不在同一屏幕上时。
单一进入单词的一个经典原因是,否则,正式的语义变得难以置信地丑陋(否则,Goto被认为是有害的)。
换句话说,如果您只有1个返回,那么您的软件何时退出例程就更容易推理。这也是反对例外的论点。
通常,我最大程度地减少了早期回报的方法。
就个人而言,我更喜欢在开始时进行通过/失败状态检查。这使我可以将功能顶部的大多数最常见的故障与遵循的其余逻辑分组。
这取决于。
如果有明显的死端条件要立即检查,请提早返回,这将使运行其余功能毫无意义。*
如果该功能更复杂,并且可能具有多个出口点(可读性问题),请设置RetVal +单个返回。
*这通常可以表明设计问题。如果您发现许多方法需要在运行其余的代码之前检查某些外部/paramater状态,则可能是呼叫者应处理的东西。
使用if
在唐·诺斯(Don Knuth)关于戈托(Goto)的书中,我读到他的理由是,始终有最有可能的状况在if声明中是第一个。假设这仍然是一个合理的想法(而不是一个纯粹的考虑到时代的速度)。我会说早期的回报不是很好的编程实践,尤其是考虑到这样的事实,除非您的代码更有可能失败总比失败,否则它们经常不用于错误处理:-)
如果您遵循上述建议,则需要将该返回放在功能的底部,然后您甚至可能不会将其称为返回,只需设置错误代码并将其返回两行即可。从而实现1个条目1退出理想。
delphi特定...
我牢记的是,对于Delphi程序员来说,这是一个很好的编程实践,尽管我没有任何证据。 D2009前,我们没有原子能返回值,我们有 exit;
和 result := foo;
或者我们可能会抛出例外。
如果你必须替代
if (true) {
return foo;
}
为了
if true then
begin
result := foo;
exit;
end;
您可能会厌倦地看到您的每个功能的顶部,并且更喜欢
if false then
begin
result := bar;
...
end
else
result := foo;
然后避免 exit
共。
我同意以下声明:
我个人是Guard Remuses(第二个示例)的粉丝,因为它减少了功能的缩进。有些人不喜欢它们,因为它导致功能的多个返回点,但我认为它们更清楚。
这些天我几乎完全使用早期回报,这是一个极端的回报。我写这个
self = [super init];
if (self != nil)
{
// your code here
}
return self;
作为
self = [super init];
if (!self)
return;
// your code here
return self;
但这真的没关系。如果您的功能中有多个或两个以上的嵌套,则需要拆除它们。
我更喜欢写:
if(someCondition)
{
SomeFunction();
}
像你一样,我通常会写第一本书,但更喜欢最后一个。如果我有很多嵌套检查,通常会重构第二种方法。
我不喜欢错误处理如何从支票上移开。
if not error A
if not error B
if not error C
// do something
else handle error C
else handle error B
else handle error A
我更喜欢这个:
if error A
handle error A; return
if error B
handle error B; return
if error C
handle error C; return
// do something
顶部的条件称为“先决条件”。通过放置 if(!precond) return;
, ,您正在视觉上列出所有前提条件。
使用大型“ IF-ELSE”块可能会增加凹痕开销(我忘记了报价约3级凹痕)。
我更喜欢保留if语句。
因此,在之间选择:
if condition:
line1
line2
...
line-n
和
if not condition: return
line1
line2
...
line-n
我会选择您所描述的“早期返回”。
请注意,我不在乎提早回报或其他任何东西,我真的很喜欢简化代码,缩短if语句的尸体,等等。
嵌套如果是和for的和 可怕, ,不惜一切代价避免它们。
正如其他人所说,这取决于。对于返回值的小函数,我可能会提早编码。但是,对于相当大的功能,我喜欢在代码中始终在代码中占有一席之地,我知道我可以在返回之前将其执行。
我在功能级别练习失败。它使代码保持一致和清洁(对我以及与我一起工作的人)。因此,我总是很早就回来了。
对于某些经常检查的条件,您可以使用AOP实现这些检查的方面。