如何在数组中保存过程地址然后在Delphi中使用它们

Kaz*_*rus 2 delphi procedure restore save memory-address

我有Tsqlquery,大多数字段使用事件Onchange.我需要在运行时以硬编码方式切换它们(例如Table.fieldbyname('ABC').Onchange:= Nil;)之后我需要打开它们(例如Table.fieldbyname('ABC'). Onchange:= TableABCChange;)我确实尝试使用指针数组并使用它如下:

var P:array [1..100] of Pointer;
begin
for i:=0 to Table.fields.count-1 do
 begin
    {save and switch them off} 
    P[i]:=@Table.fields[i].Onchange; 
    @Table.fields[i].Onchange:=Nil;
 end;
Run Code Online (Sandbox Code Playgroud)

但我不知道如何打开它们

for i:=0 to Table.fields.count-1 do
 begin
    {restore and switch them on} 
    Table.fields[i].Onchange:=P[i]; <---- ERROR
 end;
Run Code Online (Sandbox Code Playgroud)

我该怎么办?

Dav*_*nan 9

这些事件处理程序是方法指针,因此不能用单个指针表示.它们实际上由两个指针表示:一个指向数据(即对象实例),另一个指向代码.

您也在数组边界外访问.您定义了一个具有低索引1和快速访问索引的数组0.你还硬编码其上限100有些风险.您需要动态数组.

此外,通过使用@禁用类型化检查指针的默认编译器选项,您将抑制某些编译器键入检查代码的能力.

OnChange事件实际上是一个TFieldNotifyEvent方法指针.有了这些知识,您的代码应该像这样编写:

var 
  SavedChangeEvents: array of TFieldNotifyEvent;
....
// save and set event handler to nil
SetLength(SavedChangeEvents, Table.Fields.Count);
for i := 0 to Table.Fields.Count-1 do
begin
  SavedChangeEvents[i] := Table.Fields[i].OnChange; 
  Table.Fields[i].OnChange := nil;
end;
....
// restore
for i := 0 to Table.Fields.Count-1 do
begin
  Table.Fields[i].OnChange := SavedChangeEvents[i];
end;
Run Code Online (Sandbox Code Playgroud)

请注意,我在任何时候都不使用@运算符.让你的目标永远不要使用过程类型的运算符.避免这种使用允许您让编译器检查类型安全性.同时,启用键入的检查指针.