Click here to Skip to main content
15,867,686 members
Please Sign up or sign in to vote.
4.80/5 (8 votes)
See more:
I was asked this question in an interview, and either I'm suffering from brain-lock or just plain dumb, but I didn't have an answer.

Anyone?

Marc

Posted

I revisited your question after looking at your last question.

First note is: all, absolutely all delegate instances in .NET are multicast. I mean, some delegate instances have only one handler in its invocation list, but in all such cases "+=" creates a multicast interface instances with two handlers. They all have an invocation list as a member, even each member of invocation list, paradoxically. What is interesting, "+=" never adds anything to existing delegate instance: delegate instances are immutable. A brand-new delegate instances and a brand new reference to it is created in response to "+=". The immutability of delegate instance is done to improve multithreading. Finally, why do I talk about delegate instances? Take a type of a delegate instance. Is it a delegate type? No! A run-time type of a delegate instance is some… class. Get a type and use Reflection to see. I write about it in my article Dynamic Method Dispatcher[^].

Now, let's move to events. Here is my statement: each and every behavior of events can be implemented using just delegate and delegate instances, without any exclusion. Not visa versa. So, what's the benefits of events over delegate instances? Limitations!

For example: whatever you do, you can invoke event only in its declaring class, nowhere else. You cannot even invoke an event in a derived class, which is very unusual, because in other cases, every possibility is dictated by access modifiers and scope, nothing else. Why is that? I understood it well answering CodeProject questions. Many asked: "how can I call (I say: "invoke, not call" — SA) the event Button.Click?".

(Amazing logic: when a compiler says: "operation X is not allowed", typical first question is "how to do operation X"? We have a proverb: "If prohibited but very desirable then allowed" :-).)

The event Button.Click is already invoked — in the libraries. Invocation of it somewhere else, even through a class derived from Button is never really needed; one can always call some method in two places: from the Button.Click handler and somewhere else, but it would not cause invocation (which would cause the call of each handler in the invocation list), and hence it would not disrupt intended behavior of UI event system.

Invocation of this event would be foolish. And the event is what it is: a fool-proof variant of delegate instances.

And UI is not the only field of application of events. Events are used when the limitations of events are needed.

—SA
 
Share this answer
 
v3
Comments
Pete O'Hanlon 29-Feb-12 6:04am    
Good answer. And I didn't know that events couldn't be used in a derived class - mind you, it's not something I've ever needed to try, so good job again. My 5.

[Edit]My memory isn't 100% faulty - it is possible to mark an event as virtual, allowing classes to override them - I know this doesn't go against what you said, but I knew there was something about events and derived classes tickling my memory.
Sergey Alexandrovich Kryukov 29-Feb-12 15:09pm    
Thank you, Pete.

Oh, with virtual events it's even more unusual. You don't remember it clearly, just because we rarely use them. Me too.
In brief: virtual even cannot be invoked even in the declaring class.

More exactly, you can just add "virtual" and trigger it in the same class. But this "virtual" would be useless without "add" and "remove" methods (I would suggest prohibit "virtual" without add/remove by syntax): such event could not be overridden in any way in derived class. So, we should only consider virtual/abstract events with add/remove which could be overridden in a derived class. But syntax will not allow you to invoke such event at all, even in the declaring class!

Why such limitation in invocation? Because it would defeat the purpose of add/remove. You can only trigger the even indirectly, by invocation of the implementing delegate instance which gets handlers to be added to its invocation list via "add". And, from this moment, the door to abuse is opened again, because one could foolishly give too much access to this implementing delegate instance, use it outside of the declaring class or outside of derived classes, etc. But this would be the same thing as excessive access to any other implementation detail, violation of good encapsulation practice. And practically, this is fine: if some developer manages to struggle through the syntax for virtual event with overridden add/remove successfully, we can hope this person knows what she or he is doing.

[EDIT]
I clarified the sentence where I explain the role of implementing delegate instance and "add" method. This instance is not passed through "add", but a handler is passed to "add" or "remove". This is a different delegate instance, used to change implementing delegate instance. The Microsoft article referenced above shows the implementation.
[END EDIT]

Well, this topic could be a matter of another short article. Would it be interesting?

I would like to close-up this discussion for now. Please see:
http://msdn.microsoft.com/en-us/library/hy3sefw3.aspx,
http://blogs.msdn.com/b/samng/archive/2007/11/26/virtual-events-in-c.aspx.

Please also see my comment to the answer by Shameel.
--SA
Pete O'Hanlon 29-Feb-12 15:17pm    
Thanks for that. That was an interesting detour into the more esoteric sides of the language, and why constraints are placed by the language designers.
Sergey Alexandrovich Kryukov 29-Feb-12 15:48pm    
My pleasure.
--SA
Espen Harlinn 29-Feb-12 15:02pm    
5'ed!
Are you are already aware Marc, the event mechanism is just a syntactic sugar over the delegate model, just like a Property is a syntactic sugar over getters and setters.

As SAKryukov has rightly pointed out, events are all about restrictions. The compiler enforces certain restrictions over the delegates declared with the 'event' modifier so that only the declaring class can invoke the event.

It also helps us (the old VB programmers) to follow the code easily, you have a mental mapping that an event signifies the change of state in an object whereas delegates do not necessarily imply that.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 29-Feb-12 13:50pm    
I must note that the events do not imply change in state; no more than delegate instances do; neither in "implied" semantics nor in common practice.

I would not call Button.Click semantically carrying a meaning of a change in state, for a stateless button. A button with states could do in: PressingDown, PressedDown, BeingReleased, Released. A usual button gives no access to states, because it is returned to the same state after click, and this is usual. It only can be used for a state change (and I always vote for not doing it), but not in UI -- in the model where the developer plays the role of the user of the UI.

In other words, the topic of "change in state" is totally neutral to delegate and events. Semantically, event is event, state is state, and the change in state is just one of possible semantics for the events, like in LayoutChanged.

If you want to outline the difference in uses, you could note that delegate instances are not used for events at all. But this is not related to the nature of events and delegate instances. It's just because events are already used to carry the event semantics. Why using any other tool for that? But delegate instances could be used to carry event semantics as well; it's just nobody need it.

The fundamental role of delegates is different -- serving to represent methods as first-class objects, in the spirit of functional programming.

--SA
Events can make sure: using += or -=, but not = directly.
 
Share this answer
 
Comments
Pete O'Hanlon 6-Dec-10 15:12pm    
What does this have to do with Marc's question? He's what I would call a .NET expert, and your question doesn't add anything. He's well aware of how you hook up events; his question is why do we have events when you can achieve the same thing with a multi cast delegate.
Sergey Alexandrovich Kryukov 28-Feb-12 22:43pm    
Exactly. I recently re-visited this question and suggested a real answer. Please see if you are curious.
--SA
Pete O'Hanlon 29-Feb-12 6:03am    
Now when you put your response like that, I actually want to go and read your answer. It's just the right tone to get me interested. Good job.
Marc Clifton 29-Feb-12 7:20am    
SAKryukov is trolling - I posted that question 3 years ago, then I posted a question yesterday, and now it seems like he's taken it upon himself to find other questions I've asked. I suppose I should take the high road and assume he's trying to be helpful.
Pete O'Hanlon 29-Feb-12 7:30am    
Ahhh, I see. I like the spread of time between your posting of questions;)


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900