当实现具有以下定义的事件时,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中这一行作为对过程的引用不是TMethod吗?
if TMethod(handlers[i]) = TMethod(handler) then发布于 2022-05-18 11:59:32
原因是编译器可能在添加的位置和删除它们的位置之间创建匿名方法的不同实例。
请查看以下代码:
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.您将注意到,在B和C中,它将打印False,因为传递给Add和Remove的两个匿名方法彼此不同。在B中,这一点在C中是显而易见的,但编译器实际上将代码转换为:
procedure C;
begin
Add(procedure begin A(); end);
Remove(procedure begin A(); end);
end;这意味着,如果要将IEvent<>与方法引用类型一起使用并能够删除,则需要保留添加的引用,以便使它们相等,从而能够在调用Remove时找到引用。
在TEventBase内部,引用都是作为TMethod处理的,这与此无关--当传递匿名方法时,它将被转换为TMethod。毕竟,匿名方法类型是一个由编译器创建的对象支持的接口,它使进行这种转换成为可能,并且需要保留添加的引用以删除它。
https://stackoverflow.com/questions/72232429
复制相似问题