Delphi Tokyo异常会阻止设置功能结果

时间:2017-09-28 10:19:35

标签: delphi exception

发现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"。 这是一个东京错误还是不应该像这样处理异常?

2 个答案:

答案 0 :(得分:15)

东京的行为是正确的。引发异常的函数不返回值。到目前为止,您一直依赖于实现细节。

考虑以下代码:

Result:=FuncTest;

执行如下:

  1. FuncTest被召唤。
  2. Result已分配。
  3. 现在,因为步骤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子句。