Event<T> Dont remove reference to procedure.
Hi,
Using a reference to procedure as the event type, the method Remove don't remove the event handler. No issues firing and invoking the added events.
Using procedure ... of object the removal works fine, but it doesn't work for anonymous methods.
Comments (5)
-
repo owner -
reporter No, isn't that.
Something like:
TMyObject = class public procedure Handler; end; x := TMyObject.Create; e.Add(x.handler); e.Invoke(); e.Remove(x.handler); x.Free;
It only works if I make
TMyProc = procedure of object;
But when I make that, I cannot do anymore:
e.Add(procedure begin MyHandler end);
I agree and know what you explained, but it isn't the issue.
-
repo owner Yes, it is exactly that problem just that it even appears within the same routine.
Look at the generated asm:
Project1.dpr.32: e.Add(x.handler); 004D986F 8B1548344E00 mov edx,[$004e3448] 004D9875 85D2 test edx,edx 004D9877 7403 jz $004d987c 004D9879 83EAF0 sub edx,-$10 // <- 004D987C B844344E00 mov eax,$004e3444 004D9881 E8FEE7FFFF call {Spring}Event<Project1.TMyProc>.Add Project1.dpr.33: e.Invoke(); 004D9886 8D55EC lea edx,[ebp-$14] 004D9889 B844344E00 mov eax,$004e3444 004D988E E829E7FFFF call {Spring}Event<Project1.TMyProc>.GetInvoke 004D9893 8B45EC mov eax,[ebp-$14] 004D9896 8B10 mov edx,[eax] 004D9898 FF520C call dword ptr [edx+$0c] Project1.dpr.34: e.Remove(x.handler); 004D989B 8B1548344E00 mov edx,[$004e3448] 004D98A1 85D2 test edx,edx 004D98A3 7403 jz $004d98a8 004D98A5 83EAF4 sub edx,-$0c // <- 004D98A8 B844344E00 mov eax,$004e3444 004D98AD E8FAE7FFFF call {Spring}Event<Project1.TMyProc>.Remove
Step into Add and Remove and see for yourself that the passed values differ. If you want to use it that way then assign x.Handler to a local variable of the anonymous method type and Add/Remove that one.
-
reporter Got it.
It appears to be a bug on delphi side then, because it is the same method, and it works correctly if you change the type to "procedure of object".
It is like the compiler is generating:
e.Add(procedure begin x.Handler end);
What is different to what we wrote.
-
repo owner - changed status to invalid
- Log in to comment
Show some code please - I have a guess why it does not work.
To explain what my guess is - I assume you have code that looks like this:
Now to answer the question why it does not remove the procedure again we have to look at how the compiler actually implements this.
It basically does this when adding:
and the same for the Remove call. So the anonymous methods created inside the AddHandler and RemoveHandler are different. You can actually see that in the debugger when stopping inside of MyHandler:
Now if you step into the Event<T>.Remove method you can see this in the local variables: