In delphi 7, is `try … except raise; end;` meaningful at all?
在我维护的一些Delphi7代码中,我注意到了以下许多实例:
1 2 3 4 5 6 7 8 | with ADOQuery1 do begin // .. fill out sql.text, etc try execSQL; except raise; end; end; |
在我看来,这些尝试块可以被删除,因为它们什么都不做。不过,我对可能出现的细微副作用持谨慎态度。
有人能想到任何一种情况,在这种情况下,如果没有这些块,这些块实际上可以做任何不可能发生的事情吗?
在此上下文中,引发操作没有效果,应将其移除,因为它只是简单地重新引发异常块刚刚捕获的异常。提升通常用于在没有适当的错误处理可用时将控制转移到块的末尾。在下面我们将处理自定义异常,但任何其他异常都应在其他地方处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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; |
注意,在没有"加薪"的情况下,有相似的外形,这确实会产生吃/隐藏任何例外情况的副作用。非常不道德的开发人员的实践,他们希望在竞争中继续占据一席之地。
1 2 3 4 5 6 7 | with ADOQuery1 do begin // .. fill out sql.text, etc try execSQL; except // no handler so this just eats any"errors" end; |
删除上面代码段中的except代码没有任何区别。你可以(我相信你应该这样做,因为这会降低可读性)删除它。
除了允许原始程序员在"引发"上放置一个断点,并在源代码中看到异常更接近其可能原因之外,此代码什么也不做。从这个意义上说,它是一种非常合理的调试技术。
我可能回答得有点快,看最后…就像它一样,它对应用程序是无用的。时期!
现在站在"为什么"的一边。如果存在/曾经/将来/现在/正在其他地方/在提升前插入某种日志代码,则可以标准化异常处理:
1 2 3 4 5 6 7 8 9 10 | try execSQL; except // Log Exception.. on E: Exception do begin LogTrace(Format('%s: Exception Message[%s]',[methodname, E.Message])); raise; end; end; |
或清除代码:
1 2 3 4 5 6 | try execSQL; except //some FreeAndNil.. raise; end; |
更新:有一种情况下,我会看到一些使用,就像它是……为了能够在
好吧,这里有两个问题。
首先,它是有意义的:如果execsql抛出异常,它会被try块捕获并转发到except。然后它被提升转发到下一个更高的块。
第二,它有用吗?大概不会。几乎可以肯定,这是三件事之一的结果:
事实上,我应该把这个作为评论贴给弗兰?OIS的答案,但我不知道是否可以在那里插入格式化代码:(所以我把这个作为答案发布。
2MGHIE:
The second one is completely unidiomatic, one would use finally instead.
< /块引用>< /块引用>
不,"finally"将始终清除对象。例外"—只有例外。考虑函数的情况,它创建、填充和返回一个对象:
1
2
3
4
5
6
7
8
9
10 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"块,那么在"…"中出现异常时,将出现资源泄漏。
当然,你可以用"finally"检查exceptobj,但是…不是很难看吗?
除了重新引发一个异常外,此代码什么也不做,该异常将在没有此try-except块的情况下完全就绪地引发。您可以安全地将其移除。
标题包含了相当广泛的问题,而它的解释给出了一个更具体的例子。所以,我对这个问题的回答,如它是如何从这个例子中得到的,可以毫无疑问地为这里所说的内容增加任何有用的内容。
但是,也许布罗格比尔德真的想知道这对
try ... except raise; end 是否有意义。在Delphi7中,如果我记得正确的话,Exit 会触发try-finally 块的finally 部分(好像它是某种异常)。有人可能认为这样的行为不适合他们的任务,而使用所讨论的结构是一个很好的解决方法。只是在那里使用一个单独的
raise; 仍然是很奇怪的,但是正如查理所观察到的那样,我们应该讨论有用性而不是意义性。