发现Delphi Tokyo中的异常处理与以前的Delphi版本略有不同。
function FuncTest: integer;
begin
Result := 1;
try
raise Exception.Create('Error Message');
finally
Result := 2;
end;
end;
function Test:integer;
begin
Result:=0;
try
Result:=FuncTest;
finally
ShowMessage(Result.ToString);
end;
end;
在早期的Delphi版本中,消息框显示在这里" 2",东京 - " 0"。 这是一个东京错误还是不应该像这样处理异常?
答案 0 :(得分:15)
东京的行为是正确的。引发异常的函数不返回值。到目前为止,您一直依赖于实现细节。
考虑以下代码:
Result:=FuncTest;
执行如下:
FuncTest
被召唤。Result
已分配。现在,因为步骤1引发了异常,所以步骤2不会执行。
如果有的话,我会说你从早期版本报告的行为是可疑的。在这个功能中:
function Test:integer;
begin
Result:=0;
try
Result:=FuncTest;
finally
ShowMessage(Result.ToString);
end;
end;
语句Result:=FuncTest
引发异常,因此该语句不应修改Result
。另一种思考方式是调用函数但不执行赋值。
Delphi ABI的一个问题是函数返回值有时被实现为隐式var
参数。这意味着任务可能会也可能不会发生。为了证明:
{$APPTYPE CONSOLE}
uses
System.SysUtils;
type
TRec1 = record
X1: NativeInt;
end;
TRec2 = record
X1: NativeInt;
X2: NativeInt;
end;
function GetRec1: TRec1;
begin
Result.X1 := 1;
raise Exception.Create('');
end;
function GetRec2: TRec2;
begin
Result.X1 := 1;
raise Exception.Create('');
end;
procedure Main;
var
Rec1: TRec1;
Rec2: TRec2;
begin
Rec1 := Default(TRec1);
Writeln(Rec1.X1);
try
Rec1 := GetRec1;
except
end;
Writeln(Rec1.X1);
Rec2 := Default(TRec2);
Writeln(Rec2.X1);
try
Rec2 := GetRec2;
except
end;
Writeln(Rec2.X1);
end;
begin
Main;
Readln;
end.
输出:
0 0 0 1
这是相当令人失望的。不应该修改调用者的变量,但使用隐式var
参数而不是值返回允许这种泄漏。在我看来,这是Delphi ABI设计中的一个严重缺陷,这是一个你在大多数其他语言中都找不到的缺陷。
在您的代码中,没有var
参数,因为返回类型是在寄存器中传输的。在这种情况下,任何输出2
的Delphi版本都会被破坏。
但从根本上说,你的代码在预期上是错误的。如果函数引发异常,那么您必须假设返回值是不明确的。
最后,您的代码会在XE3和XE7中输出0
,所以我想知道您需要多长时间才能看到2
的值。
答案 1 :(得分:0)
考虑一下:
function FuncTest: integer;
begin
Result := 1;
try
try
raise Exception.Create('Error Message');
except
{ do nothing }
end
finally
Result := 2;
end;
end;
不要认为“最终”是在本地处理异常,而不是“返回异常”。要在本地处理它,需要一个LOCAL try-except子句。