8

在我维护的一些 Delphi 7 代码中,我注意到以下很多实例:

with ADOQuery1 do begin
  // .. fill out sql.text, etc
  try
    execSQL;
  except
    raise;
  end;
end;

在我看来,这些 try 块可以被删除,因为它们什么都不做。但是,我对可能的微妙副作用持谨慎态度。

谁能想到这些块实际上可以做任何没有它们就不会发生的事情?

4

8 回答 8

10

在这种情况下, raise 操作没有任何效果,应该被删除,因为它只是重新引发异常块刚刚捕获的异常。raise 通常用于在没有适当的错误处理可用时将控制转移到块的末尾。下面我们处理自定义异常,但任何其他异常都应在其他地方处理。

try
  someOperation;
except
  on e: ECustomException do
    SomeCustomHandelr;
  else
     begin
       // the raise is only useful to rethrow the exception to an encompasing 
       // handler.  In this case after I have called my logger code. as Rob
       // mentioned this can be omitted if you arent handling anything because
       // the compiler will simply jump you to the next block if there is no
       // else.
       LogUnexpectedException('some operation failed',e);
       raise;
     end;
end;

请注意,没有“加注”的类似外观形式确实具有吃/隐藏任何异常的副作用。非常肆无忌惮的开发商的做法,他们希望能在竞争中占据一席之地。

with ADOQuery1 do begin  
  // .. fill out sql.text, etc  
  try    
    execSQL; 
  except
    // no handler so this just eats any "errors"    
  end;
于 2009-04-30T02:27:12.733 回答
6

删除上面代码片段中的 except 代码没有任何区别。您可以(而且我相信您应该这样做,因为它会降低可读性)删除它。

于 2009-04-30T02:17:12.350 回答
2

好的,这里真的有两个问题。

首先,它有意义的:如果 execSQL 抛出异常,它会被 try 块捕获并转发给 except。然后它被加注转发到下一个更高的块。

第二,有用吗?可能不是。这几乎可以肯定是以下三件事之一的结果:

  1. 一个头发尖的人写了一个编码标准,上面写着“所有可以抛出异常的操作都必须在 try 块中”。
  2. 有人打算回来并将execSQL声明中的异常转换为其他更有意义的异常。
  3. 新人不知道他们写的内容与让外部环境担心异常是同构的,因此认为他们必须转发它。
于 2009-04-30T02:30:41.257 回答
2

可能我回答的有点快,看最后……
就是这样,对应用没用
时期!

现在在“为什么”方面。如果 /was/will be/is 在其他地方/在 raise 之前插入了某种日志记录代码,则可能是标准化异常处理:

  try
    execSQL;
  except
    // Log Exception..
    on E: Exception do
    begin
      LogTrace(Format('%s: Exception Message[%s]',[methodname, E.Message]));
      raise;
    end;
  end;

或清理代码:

  try
    execSQL;
  except
    //some FreeAndNil..
    raise;
  end;

更新:在 1 种情况下,我会看到一些用途,就像它一样............
能够raise在线上放置一个断点,以便有机会查看该块的上下文中发生了什么代码。

于 2009-04-30T03:37:57.180 回答
2

除了允许原始程序员在“引发”上放置断点并在源中更接近其可能原因之外,此代码什么也不做。从这个意义上说,它是一种完全合理的调试技术。

于 2009-04-30T06:40:10.377 回答
1

实际上,我应该将此作为对弗朗索瓦答案的评论发布,但我不知道是否可以在其中插入格式化代码:(所以我将其发布为答案。

2mghie:

第二个是完全不习惯的,一个会使用 finally 代替。

不,“finally”总是会清理对象。“例外” - 仅在例外情况下。考虑函数的情况,它创建、填充和返回一个对象:

function CreateObj: TSomeObj;
begin
  Result := TSomeObj.Create;
  try
    ... // do something with Result: load data, fill props, etc.
  except
    FreeAndNil(Result); // oops: bad things happened. Free object to avoid leak.
    raise;
  end;
end;

如果你把“finally”放在那里 - 函数将始终返回 nil。如果您完全省略“try”块 - 如果“...”中出现异常,则会出现资源泄漏。

PS 当然,你可以使用“finally”并检查ExceptObj,但是......不是很丑吗?

于 2009-04-30T04:38:05.600 回答
0

标题包含一个相当广泛的问题,而它的解释给出了一个更具体的例子。因此,我对这个问题的回答是如何从示例中进行的,无疑可以为这里已经说过的内容添加任何有用的东西。

但是,也许Blorgbeard确实想知道它是否有意义try ... except raise; end在 Delphi 7 中,如果我没记错的话,Exit会触发块的finally一部分try-finally(就好像它是某种异常一样)。有人可能会认为这种行为不适合他们的任务,使用有问题的结构是一种很好的解决方法。

只是在那里使用单曲仍然会很奇怪raise;,但是我们应该谈论有用性而不是意义,正如查理巧妙地观察到的那样。

于 2009-04-30T14:57:14.927 回答
0

这段代码除了重新引发一个在没有这个 try except 块的情况下已经被引发的异常之外什么都不做。您可以安全地删除它。

于 2009-04-30T18:25:08.157 回答