我正在维护一些 Delphi 7 代码,发现有很多如下的实例:
with ADOQuery1 do begin
// .. fill out sql.text, etc
try
execSQL;
except
raise;
end;
end;
我认为这些try块可以被移除,因为它们没有做任何事情。然而,我担心可能会有微妙的副作用。
有人能想到这些块实际上可能会发挥作用的情况吗?如果没有它们,是否会发生任何事情?
我正在维护一些 Delphi 7 代码,发现有很多如下的实例:
with ADOQuery1 do begin
// .. fill out sql.text, etc
try
execSQL;
except
raise;
end;
end;
我认为这些try块可以被移除,因为它们没有做任何事情。然而,我担心可能会有微妙的副作用。
有人能想到这些块实际上可能会发挥作用的情况吗?如果没有它们,是否会发生任何事情?
在这种情况下,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;
要注意的是,有一种类似的表单没有使用"raise",但确实有隐藏任何异常的副作用。这是非常不道德的开发人员使用的做法,他们希望已经转向竞争对手的职位。
with ADOQuery1 do begin
// .. fill out sql.text, etc
try
execSQL;
except
// no handler so this just eats any "errors"
end;
在上面的代码段中删除except代码不会有任何影响。你可以(我相信你应该,因为它降低了可读性)将其删除。
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
行上设置断点,以便有机会查看该代码块的上下文中发生了什么。好的,这里有两个问题。
首先,它是有意义的:如果execSQL抛出异常,它会被try块捕获并转发到except。然后通过raise将其转发到下一个更高的块。
第二,它是否有用?可能不是。它几乎肯定是以下三种情况之一的结果:
这段代码除了让原始程序员在“Raise”处设置断点并更接近异常可能的原因之外,没有其他作用。从这个意义上说,这是一种完全合理的调试技术。
实际上,我应该将这个作为评论发布到François的回答中,但我不知道是否可以在那里插入格式化的代码 :( 所以我将其发布为答案。
2mghie:
第二个完全不符惯用法,应该使用finally。
不,“finally”会始终清理对象。“Except”-只有在异常情况下才会清理。考虑一个创建、填充并返回对象的函数的情况:
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;
标题包含了一个相当广泛的问题,而它的解释则给出了一个更具体的例子。因此,我的回答关于如何从这个例子中进行处理,可能无法为已经在这里说过的内容添加任何有用的东西。
但是,也许 Blorgbeard确实想知道是否有意义去使用 try ... except raise; end
。在Delphi 7中,如果我记得正确的话,Exit
会触发try-finally
块的finally
部分(就像它是某种异常一样)。有些人可能认为这种行为不适合他们的任务,并且使用所讨论的结构是一个相当棘手的解决方法。
只是在那里使用单个raise;
仍然很奇怪,但是我们应该谈论有用性而不是意义,正如Charlie所观察到的那样。
这段代码除了重新抛出一个本来就会在没有该try except块的情况下抛出的异常外,什么也不做。你可以安全地将其删除。