2

对于我的一些程序和函数,我已经对参数进行了各种检查,以便在参数以某种方式超出范围时强制停止执行。我发现最好在我自己的代码中检查这一点,而不是由于内存写入错误而导致异常崩溃。

考虑简单的代码:

PROCEDURE Test(OneDigitNumbers:BYTE);
BEGIN
  IF OneDigitNumbers>9 THEN ProduceErrorMessage;
END;

begin
  Test( 1);
  Test( 2);
  Test( 9);
  Test(12);
end.

实际上产生错误消息我没有问题,我唯一的“问题”是Delphi中的调试器总是指向创建异常的过程。是否有创建此异常或错误消息的方法,以便调试器指向参数超出范围的行?在我的示例中,它应该指向:

Test(12);

并且可能会说“参数超出范围。有效范围是 0-9。传递的参数是:12”

甚至说这是不可能的答案也会很有用(如果您确定这是不可能的),因为那样我就会忘记这一点并制定一种替代的调试方法。

4

4 回答 4

5

要回答所问的问题,您可以使测试函数内联:

procedure Test(OneDigitNumbers: byte); inline;

然后编译器会将 Test 的代码写入每个调用函数。虽然你可以这样做,但我的建议是你不这样做。这只是一个技巧,但我认为它对你没有帮助。

如果要在返回地址引发异常,可以这样做:

raise Exception.CreateFmt(
  'Exception blah blah at %p.',
  [ReturnAddress]
) at ReturnAddress;

如果您想在堆栈中更进一步,那么您将不得不使用类似CaptureStackBackTrace. 将回溯跟踪与 raise at 结合起来,您可以在调用堆栈中的任何位置引发异常,如果您真的认为这是个好主意。正如我在下面解释的那样,我认为这不是一个好主意。

如果您使用良好的调试工具,例如 madExcept,那么 madExcept 错误报告中的调用堆栈将告诉您发生错误时需要知道的所有信息。


通过注释中的额外说明,您似乎真正想要发生的是异常包含来自调用堆栈更高层的信息。在我看来,要求被调用者报告有关其调用者的信息是违反封装的。所以如果你想包含来自调用者的信息,让调用者捕获异常,添加信息,然后重新引发。

于 2013-04-14T08:18:12.340 回答
2

您正在寻找子范围类型

type
  TOneDigitNumber = 0..9;

procedure Test(OneDigitNumbers: TOneDigitNumber);
begin
  // Do something
end;

begin
  Test( 1);
  Test( 2);
  Test( 9);
  Test(12);   // compiler error '[DCC Error] MyStuffTest.pas(33): E1012 Constant expression violates subrange bounds
end.
于 2013-04-14T08:00:26.573 回答
1

对我对您的问题的评论进行一些详细说明

type
  EMyOwnRangeError = class(ERangeError)
    // You can also add your own member variables for easier inspection
  public
    constructor CreateFrom(const aRangeError: ERangeError);
  end;

constructor EMyOwnRangeError.CreateFrom(const aRangeError: ERangeError);
begin
  // Do whatever you need to inspect the call stack in aRangeError 
  // and modify the message and/or set any extra member variable that you
  // you define on EMyOwnRangeError.
  // No help from me on this, quite simply because I don't have Delphi 
  // installed on the machine I am currently working at.
end;

procedure MySpecialTest(const aWhatever: Byte);
begin
  try
    if (aWhatever < 0) or (aWhatever > SOMEUPPERRANGE) then
      raise ERangeError.Create;

    // Normal code for MySpecialTest

  except
    on E: ERangeError do raise EMyOwnRangeError.CreateFrom(E);
    else
      raise; // Make sure other exceptions are propagated.
  end;
end;
于 2013-04-14T09:17:59.473 回答
0

我现在基本上测试了我从 David Heffernan 那里得到的想法中的方法。我只是在我的一个可重用单元中添加了这个简单的代码:

PROCEDURE TestError(Par:BYTE);
  BEGIN
    TRY
    FINALLY
      IF Par>9 THEN Raise Exception.CreateFmt('Error Blah blah blah at ',[Par]) AT @Par;
    END;
  END;

当使用高于 9 的参数调用此过程时,它会强制异常。Delphi 询问“Break or Continue”,然后我单击“Break”。

结果几乎是我想要的,但它是如此接近以至于我可以忍受。调试器在调用过程之后的行上弹出一条漂亮的红线。

我也尝试了没有 TRY-Finally-End 的情况,然后这是完全错误的,实际上从调用堆栈中显示了另一个级别的红线..

反正。我觉得这个结果比我以前的结果要好得多。现在我的调试将是一种快乐而不是痛苦。谢谢 :)

于 2013-04-14T17:02:05.177 回答