Spring4d如何使事件处理引用过程?



当使用下面的定义实现事件时,Spring4D将添加和调用方法,但不会删除处理程序(使用IEvent. remove (MyProc)),因为它不识别它。

{$M+}
TaskItemChangeEvent = reference to procedure(const TaskItem: ITaskItem; Event: TTaskListEvent);

下面的代码可以工作,但是我不希望被强制绑定到一个对象。

{$M+}
TaskItemChangeEvent = procedure(const TaskItem: ITaskItem; Event: TTaskListEvent) of Object;

我认为问题在于TEventBase中的这一行。Remove作为对procedure的引用不是TMethod?

if TMethod(handlers[i]) = TMethod(handler) then

原因是编译器可能会在添加和删除匿名方法的地方创建不同的实例。

请看下面的代码:

var
proc: TProc;
procedure Add(p: TProc);
begin
proc := p;
end;
procedure Remove(p: TProc);
begin
Writeln(PPointer(@proc)^ = PPointer(@p)^);
end;
procedure A;
var
p: TProc;
begin
p := procedure begin end;
Add(p);
Remove(p);
end;
procedure B;
begin
Add(procedure begin end);
Remove(procedure begin end);
end;
procedure C;
begin
Add(A);
Remove(A);
end;
begin
A;
B;
C;
Readln;
end.

您将注意到,在BC中,它将打印False,因为传递给AddRemove的两个匿名方法彼此不同。虽然在B中很明显,但在C中它不是,但编译器实际上将代码转换为:

procedure C;
begin
Add(procedure begin A(); end);
Remove(procedure begin A(); end);
end;

这意味着如果你想使用IEvent<>和一个方法引用类型,并且能够删除,你需要保持你添加的引用,以便它们相等,从而能够在调用Remove时被找到。

TEventBase内部的引用都被作为TMethod处理的事实与此无关-当传递一个匿名方法时,它被转换为TMethod。毕竟,匿名方法类型是由编译器创建的对象支持的接口,这使得进行这种转换成为可能,并导致必须保留为了删除它而添加的引用。

最新更新