Delphi 是德尔福';什么是退出声明危险?

Delphi 是德尔福';什么是退出声明危险?,delphi,Delphi,阅读Delphi的Exit声明(例如,请参阅),我不能忽视,写下它,每个作者都有责任给出一条建议,例如: 警告:小心使用-跳转是一个与结构化编码不一致的概念-它使代码维护变得困难 现在,我来自UNIX中的C和C++,我熟悉重新入选的问题,但老实说,我无法理解为什么在德尔菲法返回到它的自然终点之前,它应该是邪恶的。 除非Delphi中的每个函数和过程都被视为可重入者 我错过了什么?有两种思想流派 一个学派认为函数应该有一个单一的退出点。许多编码标准都将此作为一项规则加以实施。这样做的动机来自于用g

阅读Delphi的
Exit
声明(例如,请参阅),我不能忽视,写下它,每个作者都有责任给出一条建议,例如:

警告:小心使用-跳转是一个与结构化编码不一致的概念-它使代码维护变得困难

现在,我来自UNIX中的C和C++,我熟悉重新入选的问题,但老实说,我无法理解为什么在德尔菲法返回到它的自然终点之前,它应该是邪恶的。 除非Delphi中的每个函数和过程都被视为可重入者


我错过了什么?

有两种思想流派

一个学派认为函数应该有一个单一的退出点。许多编码标准都将此作为一项规则加以实施。这样做的动机来自于用goto、多个出口等维护充满大型函数的意大利面代码的艰苦经验

另一个学派认为意大利面编码是不好的,但我们应该务实,根据编码方式的优劣来判断编码方式,而不是遵循教条规则。例如,许多程序员认为,当您不使用
exit
时,保护子句比深度缩进的函数更可取。作为一个示例,请考虑Martin Fowler优秀重构目录中的以下示例:


从根本上说,这一切都归结于个人偏好。我个人鼓励使用保护条款,但不要在漫长的程序中随意使用退出。

你没有注意到它没有说“不要使用这个”或“退出是邪恶的”;它说“小心使用”,并说这会使维护变得困难。例如,如果你有一个大的方法,中间有一个这样的线,你可能完全错过它:

if aLocalObject.CheckSomeValue(aParameter) <> RIGHT_VALUE then Exit;
如果是aLocalObject.CheckSomeValue(aParameter)右键\u值,则退出;
是的,不幸的是,我以前确实见过这样的东西(

许多问题可以通过一些经验法则来缓解:

  • 始终将
    Exit
    (和
    Break
    Continue
    )语句放在它们自己的行中。这会使它们更难被忽略
  • 喜欢小方法而不是大方法,在合理的时候把大方法分解成小方法。(合理的时候!这不是一条绝对的规则,过于热心地应用它会让事情变得更糟而不是更好。记住爱因斯坦的名言:“让一切尽可能简单,但不要简单。”)
  • 学习使用
    try/finally
    块,以便
    Exit
    退出过程是安全的,不会导致泄漏或损坏

与许多事情一样,exit在某些情况下很有用,而在其他情况下则不可用。我发现它在一些小函数中非常有用,这些小函数可以搜索某个容器,将对象从容器加载到循环中的“result”中,并查找匹配的属性。如果找到,函数可以直接退出,如果没有,则可以在l之后将结果设置为nil哦,就在“正常”返回之前

当然,在调试过程中,很少有开发人员没有在过程的顶部插入“出口”来停止它的执行


我只能同意其他海报提出的关于守卫条款、隐藏在大型复杂程序中的出口等问题。

除了David和Mason的精彩回答外,我想分享我个人的
出口
使用偏好。让我们称之为“安全守卫”,这与“万不得已的提供者”完全相反;)

基本思想是:

function Search(List: TList; Item: TObject): Integer;
begin
  for Result := 0 to List.Count - 1 do
    if List[Result] = Item then
      Exit;
  Result := -1;
end;
其他更现实的示例(来自和):

并引用Delphi帮助中关于循环变量“”在循环后可能未定义的编译器错误消息作为结束语:

如果循环留下goto或exit语句,则只能依赖for循环控制变量的最终值


+1.尽管我认为你说的是显而易见的,但你的措词却很好!如果使用正确,出口没有什么坏处。我会在适当的时候使用它。就像其他工具一样,它只是一个工具。我更喜欢在程序开始时明确退出,同时检查某些条件,而不是IF-ELSE(例如OK),这就是为什么:)我建议您在下面的文章中详细介绍同一主题。这个问题在这里并不合适,因为它需要讨论和推测。它真的应该放在更合适的地方。作者特别提到这类问题,认为它与本网站的格式和设计不符。投票迁移到程序员。链接站点因误解和低质量信息而闻名。别理它。他试图说的是单出口点的概念,但没有成功。我们可以将它迁移到程序员那里,在那里它应该作为这个概念的复制品关闭:这都是关于可读性的。没有效率问题。你链接到的网站Delphi Basics非常差,IMHO。不要用它来指导你。但在这种情况下,这是很清楚的。它给出了基于代码可维护性的退出建议,就像您的所有答案一样。这是这里唯一的问题。您的线性搜索示例就是这个用法+1的典型示例
const 
  Order: array[0..6] of String = ('B', 'C', 'A', 'D', 'G', 'F', 'E'); 

function GetStringOrder(const S: String; CaseSensitive: Boolean): Integer; 
begin 
  for Result := 0 to Length(Order) - 1 do 
    if (CaseSensitive and (CompareStr(Order[Result], S) = 0)) or 
        (not CaseSensitive and (CompareText(Order[Result], S) = 0)) then 
      Exit; 
  Result := Length(Order); 
end; 
function FindControlAtPos(Window: TWinControl; const ScreenPos: TPoint): TControl; 
var 
  I: Integer; 
  C: TControl; 
begin 
  for I := Window.ControlCount - 1 downto 0 do 
  begin 
    C := Window.Controls[I]; 
    if C.Visible and PtInRect(C.ClientRect, C.ScreenToClient(ScreenPos)) then 
    begin 
      if C is TWinControl then 
        Result := FindControlAtPos(TWinControl(C), ScreenPos) 
      else 
        Result := C; 
      Exit; 
    end; 
  end; 
  Result := Window; 
end;