在Delphi中创建或强制错误

时间:2013-04-14 07:50:37

标签: delphi

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

考虑简单的代码:

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 个答案:

答案 0 :(得分:5)

要回答问题,您可以使测试功能内联:

procedure Test(OneDigitNumbers: byte); inline;

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

如果要在返回地址处引发异常,可以执行以下操作:

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

如果你想进一步上升,那么你将不得不使用像CaptureStackBackTrace这样的东西。将后跟跟踪与up at组合,你可以在调用堆栈中的任何一点引发异常,如果真的你认为这是个好主意。我不认为这是一个好主意,正如我在下面解释的那样。

如果你使用一个好的调试工具,比如madExcept,那么madExcept错误报告中的调用堆栈会告诉你发生错误时你需要知道的所有内容。


通过注释中的额外说明,您真正想要发生的事情似乎是异常包含来自调用堆栈中较高层的信息。在我看来,要求被叫方报告有关其呼叫者的信息是违反封装的。因此,如果您想要包含来自调用者的信息,请让调用者捕获异常,添加信息并重新提升。

答案 1 :(得分:2)

您正在寻找subrange type

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.

答案 2 :(得分: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;

答案 3 :(得分: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的参数调用此过程时,它会强制执行异常。 德尔福问“打破或继续”,然后点击Break。

结果几乎是我想要的,但它非常接近,我可以忍受。 在调用该过程的人之后,调试器弹出一条漂亮的红线。

我尝试了没有TRY-Finally-End,然后它是完全错误的,实际上显示红线从callstack返回另一个级别..

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