Event handler literal identity
-
venerdì 6 luglio 2012 10:54
This is elementary but I haven't found it specified in the C# specification or the library. When you remove an event handler you don't need a reference to the same delegate (EventHandler) object:
Click += new EventHandler(frm_Click); Click -= new EventHandler(frm_Click);
(which to the best of my knowledge is completely equivalent to the shorthand)
Click += frm_Click; Click -= frm_Click;
This is so even though
object.ReferenceEquals( new EventHandler(frm_Click), new EventHandler(frm_Click));evaluates to false. So it seems that either the compiler is using some form of compile-time constant expression evaluation, or although delegates are wrapped as objects, different ones initialized with the same method name internally point to the same function in memory, and so are identical in practice even though they are wrapped as different .NET objects.
My question is, where can I find this behavior oficially specified?
Tutte le risposte
-
venerdì 6 luglio 2012 11:44
To know the identity, I will take the same example as yours, except event. Consider two EventHandler objects.
EventHandler handler1 = frm_Click; EventHandler handler2 = frm_Click;
To verify both handler1 and handler2 internally point to same function, you can run the below statement,
bool areTheyEqual = handler1.Method.Equals(handler2.Method);
Note that Method is of InPtr type which holds the address of frm_Click. The above statement returns you true because both delegates are wrappers around same function pointer.
I hope this helps.
Please mark this post as answer if it solved your problem. Happy Programming!
- Modificato AdaveshMVP venerdì 6 luglio 2012 11:45
- Modificato AdaveshMVP venerdì 6 luglio 2012 11:46
- Modificato AdaveshMVP venerdì 6 luglio 2012 11:47
- Contrassegnato come risposta Bob ShenMicrosoft Contingent Staff, Moderator giovedì 9 agosto 2012 08:25
-
venerdì 6 luglio 2012 12:13
Instead of ReferenceEqual, the system probably uses Equals or operator ==:
new EventHandler(frm_Click).Equals(new EventHandler(frm_Click)) --- is true
new EventHandler(frm_Click).Equals(new EventHandler(frm_OtherClick)) --- is false
new EventHandler(frm_Click) == new EventHandler(frm_Click) --- is true
new EventHandler(frm_Click) == new EventHandler(frm_OtherClick) --- is false
See also: Delegate.Equality operator: http://msdn.microsoft.com/en-us/library/system.delegate.op_equality(v=vs.100).aspx#Y0. Experiments give the same results.
-
venerdì 6 luglio 2012 14:09
Thank you. Nevertheless I think this should be specified in the specification. Nowhere it's even mentioned that Equals() or == be the condition on which handlers are removed from an event. The C# specification (§10.8.1) simply says "-= ... which removes a delegate from the invocation list..."
I'm marking Viorel's answer because it seems none of the properties of the Delegate class are sufficient for equality for the whole object, according to his link, although Method is one of the necessary ones, so Adavesh was also on the right track.
- Modificato Javier AP venerdì 6 luglio 2012 14:12
-
venerdì 6 luglio 2012 14:24
Thank you. Nevertheless I think this should be specified in the specification. Nowhere it's even mentioned that Equals() or == be the condition on which handlers are removed from an event. The C# specification (§10.8.1) simply says "-= ... which removes a delegate from the invocation list..."
I'm marking Viorel's answer because it seems none of the properties of the Delegate class are sufficient for equality for the whole object, according to his link, although Method is one of the necessary ones, so Adavesh was also on the right track.
I'm guessing it doesn't specify reference equality either, does it?
When you want to determine whether two objects are "the same" you use the equals method, not ReferenceEquals. It may just so happen that the Equals method uses reference equality internally, and checking reference equality first and only looking at "real" equality if false can be a nice little optimization, but you will almost never come across situations where reference equality is used instead of regular equality for a particular definition of whether two items are equal.
-
venerdì 6 luglio 2012 15:03I know all that. The question is, the specification "doesn't specify".
-
venerdì 6 luglio 2012 15:05
I know all that. The question is, the specification "doesn't specify".
My point is that if it doesn't specify you should assume it uses "Equals" to determine equality, not "ReferenceEquals". -
venerdì 6 luglio 2012 16:28I have to disagree, if a specification doesn't specify something I should assume nothing except that it's incomplete. I'd have no other sensible option than finding out by testing, which is what I did, and hope the result holds for other implementations.
-
venerdì 6 luglio 2012 16:58
I have to disagree, if a specification doesn't specify something I should assume nothing except that it's incomplete. I'd have no other sensible option than finding out by testing, which is what I did, and hope the result holds for other implementations.
You won't (or at least shouldn't) ever see anyone using "ReferenceEquals" as the definition of equality, especially unless it's specifically documented. The entire purpose of the Equals method is to specify equality, and you know, based on the design of the language, that every single object will have such a method. If you're using ReferenceEquals you're either using in the definition of some Equals method, the definition of a custom EqualityComparer of some sort, or for something other than defining equality.
As for you not assuming anything unless told; you assumed that event adding/removing used ReferenceEquals, according to your OP, and seemed to test it when that assumption was found to be false. So the issue here isn't that you haven't made any assumptions, it's that you made the incorrect one (which is fine; that happens).
-
venerdì 6 luglio 2012 17:19I did not assume at any point that ReferenceEquals() was used, on the contrary I observed that it could not be the case. I was merely asking where's this behavior specified (whether Equals() or ReferenceEquals() or any possible third or fourth option is used). And it remains unanswered, although I've given up on it. But it's always possible that someone else may have new insight, let's not derail and cluttler the thread further, everything so far is understood.
-
venerdì 6 luglio 2012 17:58
Hi,
Not 100% sure what is your issue but it seems to me you would not be surprised by the behavior if it were just integers (the situation is similar to adding int a=10 in a list of integers and removing int b=10 from the same list) and that for some reason, you feel it could have worked another way with delegates. IMO they just didn't felt it was necessary to specify this explicity here or anywhere else.
Try perhaps http://codebetter.com/davidhayden/2005/02/22/object-identity-vs-object-equality-overriding-system-object-equalsobject-obj/ , basically they thought it was obvious that you remove the value if it is "equal" rather than "identical".
Or at best you'll find in the specification some place where they discuss once for all Equals and ReferenceEquals...
Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
-
giovedì 2 agosto 2012 12:38
§7.8.5 Subtraction operator: "To determine sublist equality, corresponding entries are compared as for the delegate equality operator (§7.10.8).)"- Contrassegnato come risposta Javier AP venerdì 3 agosto 2012 10:04
-
venerdì 3 agosto 2012 10:05Louis, that's exactly what I had been looking for, but I hadn't found it. Thank you.

