when implementing an Event with the definition below Spring4D will add and invoke method but will not remove handler ( with IEvent<TaskItemChangeEvent>.Remove(MyProc) ) when asked as it does not identify it.
{$M+}
TaskItemChangeEvent = reference to procedure(const TaskItem: ITaskItem; Event: TTaskListEvent);
The following does work but I do not want to be forced to be bound to an object.
{$M+}
TaskItemChangeEvent = procedure(const TaskItem: ITaskItem; Event: TTaskListEvent) of Object;
I believe the issue is this line in TEventBase.Remove as a reference to procedure is not a TMethod?
if TMethod(handlers[i]) = TMethod(handler) then
The reason is the compiler possibly creating different instances of the anonymous method between the place where you add and where you remove them.
Look at the following code:
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.
You will notice that in B
and C
it will print False
because the two anonymous methods being passed to Add
and Remove
differ from each other. While in B
it's obvious in C
it is not but the compiler actually transforms the code into this:
procedure C;
begin
Add(procedure begin A(); end);
Remove(procedure begin A(); end);
end;
That means if you want to use IEvent<>
with a method reference type and be able to remove you need to keep the reference that you added in order for them to be equal and thus be able to be found when calling Remove
.
The fact that internally in TEventBase
the references are all handled as TMethod
has nothing to do with that - when passing an anonymous method it is being transformed into a TMethod
. After all an anonymous method type is an interface being backed by an object which the compiler creates which makes it possible to do such conversion and causes the necessity to keep the reference that was added in order to remove it.