让我先回答这个问题。
如何使编译器尽可能多地显示
编译器向您显示错误在对btnclick的调用中。
技巧是用
第5页
.
然后重新生成(!)应用程序并再次运行。
执行将停止该断点。
使用
第8页
直到错误出现。
放置断点
第5页
在生成错误的行上。
中止并重新运行应用程序。
当您到达第二个断点而不是按
第8页
按
第7页
要进入导致错误的例程,请继续按
第7页
/
第8页
直到你明白问题的真正原因。
为什么会发生这种情况?
编译器通过跟踪堆栈跟踪来追溯异常的源。
因为在您的情况下,生成异常的代码没有堆栈跟踪(因为它不是调试代码),所以编译器无法执行此技巧,而是遵循堆栈跟踪
做
有它在代码中向上移动一个级别,并在那里标记异常。
详细了解一下
你在比较苹果和橙子。
本规范(附件A):
Caption := _List[0]; // 'List index out of bounds (0)' here
与本规范完全没有共同之处(附件B):
_myArray: array [1 .. 5] of string;
....
_myArray[0]:= 'Hallo';
附件A使用TStringList类的
items
属性,其定义大致如下
(我简化了一点,但基本原理是正确的)
:
type
TStringList = class(TStrings)
strict private
FList: array of string;
....
private
procedure Put(index: integer; const value: string);
function Get(index: integer): string;
published
property Items[index: integer]: string read Get write Put; default;
// ------------------------------------------------------^^^^^^^
....
end;
注意
default
关键字
Items
所有物
这意味着当你打电话
_List[0]
,你真的在打电话
_List.Items[0]
,转换为
Caption:= _List.Getitems(0)
,因为属性上的read修饰符。
这个
违约
关键字允许您省略
.Items
.
这个
Get
代码如下:
function TStringList.Get(Index: Integer): string;
begin
if Cardinal(Index) >= Cardinal(FCount) then
Error(@SListIndexError, Index); <<-Here is the line that generates the error*
Result := FList[Index].FString;
end;
*
实际上,错误是在
Error
常规
除非您有RTL/VCL源代码
和
使用调试DCU运行时,不会中断异常(在system.classes中)单元的确切触发。
请注意,此错误不取决于范围检查,它将始终激发。
因为Delphi没有生成错误的确切行的调试信息,所以它会做下一件最好的事情,并尝试进行猜测。
短版本
stringlist是一个复杂的抽象,假装是一个数组。
调用了大量代码,使得编译器很难准确定位错误。
在附件B中:
_myArray: array [1 .. 5] of string;
....
i:= 0;
_myArray[i]:= 'Hallo';
生成范围检查错误或访问冲突。
这两个错误都发生在精确的行上,允许编译器在正确的位置停止。
短版本
这个
平原
数组是一个基本的构建块,没有对其他地方代码的隐藏调用,使得编译器很容易发现错误。
了解财产
类和记录财产(现在是类操作符)看起来像是对变量的简单赋值/操作,但实际上是对子例程的调用(可能很复杂)。