Clarifying the Relationship Between Delegates and Events

S

Smithers

I'm wanting to make sure I have an accurate understanding of the
relationship between delegates and events in .NET.

By "events in .NET" I'm referring to specifically to events defined on the
'event' keyword - not other ways to do events, like old-school callbacks.

Please consider the following event declaration:

line 1: public delegate void SomethingJustHappened(string whatHappened);
line 2: public event SomethingJustHappened MyEvent;

Are the following statements accurate? If any are not, I would appreciate it
if you would briefly explain why it is [they are] inaccurate.

1. line 1 above creates a new type. That type is an extension of
System.Delegate. So, SomethingJustHappened is a System.Delegate.

2. The "data type of the event" is SomethingJustHappened (our delegate type
from line 1). [is that how we'd say it - "data type of an event"???]

3. Because the event declared in line 2, MyEvent, IS-A
SomethingJustHappened, MyEvent IS-[also]-A System.Delegate. In other words,
event == delegate. Yes?

4.When we "register a method with an event" we are really registering the
method with the delegate upon which the event is based (or the delegate that
IS ALSO the event).

5. Conclusion #1 - an event (defined on the 'event keyword') is really a
wrapper for a delegate --- or the event is just *another name* by which we
can refer to the delegate.

6. Conclusion #2 - The conceptualization of "event" is little more than a
conceptual convenience for us to think about a specialized use of delegates.
In face, we can substitute delegates in any place where we have an event.


I appreciate your time and consideration on this. I'm wanting to understand
what's going on and not "just make it work."

-S
 
P

Peter Duniho

Smithers said:
I'm wanting to make sure I have an accurate understanding of the
relationship between delegates and events in .NET.

Your confusion is understandable. I still not quite sure I understand
why C# makes a distinction between events and delegates, except possibly
that even though they are basically the same by default, you can in fact
override the default behavior and implement an event via some other
mechanism.

Here's a recent post Jon Skeet made that I think is pretty direct:
http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/msg/be643ce2473fb217

For specifics from the C# specification, see:
http://msdn2.microsoft.com/en-us/library/aa664454(VS.71).aspx
http://msdn2.microsoft.com/en-us/library/aa664456(VS.71).aspx

(sorry for the 1.1 references...there are more recent specs available
online, but only in Word document format as near as I can tell)

With that in mind, let's look at your questions:
By "events in .NET" I'm referring to specifically to events defined on the
'event' keyword - not other ways to do events, like old-school callbacks.

Please consider the following event declaration:

line 1: public delegate void SomethingJustHappened(string whatHappened);
line 2: public event SomethingJustHappened MyEvent;

Are the following statements accurate? If any are not, I would appreciate it
if you would briefly explain why it is [they are] inaccurate.

1. line 1 above creates a new type. That type is an extension of
System.Delegate. So, SomethingJustHappened is a System.Delegate.

True, if you replace "extension" with "subclass". Disclaimer: my
understanding is that there's no difference between a Delegate and a
MulticastDelegate. But technically, events use the latter, so if I'm
wrong about there not being a difference, then SomethingJustHappened is
a subclass of a MulticastDelegate, not a Delegate.
2. The "data type of the event" is SomethingJustHappened (our delegate type
from line 1). [is that how we'd say it - "data type of an event"???]

The type of the implicitly created private field for both the event and
for the event accessor is SomethingJustHappened.
3. Because the event declared in line 2, MyEvent, IS-A
SomethingJustHappened, MyEvent IS-[also]-A System.Delegate. In other words,
event == delegate. Yes?

Not quite. By default the event translates almost directly to a
delegate. But you can override this behavior if you want, by declaring
the event accessors explicitly.
4.When we "register a method with an event" we are really registering the
method with the delegate upon which the event is based (or the delegate that
IS ALSO the event).
True.

5. Conclusion #1 - an event (defined on the 'event keyword') is really a
wrapper for a delegate --- or the event is just *another name* by which we
can refer to the delegate.

Not quite. It implicitly creates a delegate typed member in the class,
but it also creates the event accessors. It is not just another name
for the delegate.
6. Conclusion #2 - The conceptualization of "event" is little more than a
conceptual convenience for us to think about a specialized use of delegates.
In face, we can substitute delegates in any place where we have an event.

Not quite. You can only substitute delegates if your event uses the
default implementation. If you have a custom implementation of the
accessors, you can't just replace that with a simple delegate instance.

Pete
 
J

Jon Skeet [C# MVP]

Peter Duniho said:
Your confusion is understandable. I still not quite sure I understand
why C# makes a distinction between events and delegates, except possibly
that even though they are basically the same by default, you can in fact
override the default behavior and implement an event via some other
mechanism.

Well, they're really very different, but the "field-like events" of C#
make them appear quite similar *in some situations*. Even without any
extra behaviour in add/remove, they're different: if you have a public
delegate field, you can set/fetch/execute that delegate; if you have an
event you can *only* subscribe to it or unsubscribe from it. That's
from outside the class, of course - inside the class, when you
supposedly refer to the field-like event, you're actually referring to
a delegate field of the same name.

I think the best way of explaining the difference is to compare
events/delegates with properties/fields.

When you use a property, it looks the same as using a field:

x.SomeProperty = y;

But that's actually calling a method:

x.set_SomeProperty(y);

The property itself is just a pair of methods, not a storage location.
Similarly events are just pairs of methods, not storage locations. When
you do:

x.SomeEvent += y;

you're actually doing:

x.add_SomeEventHandler(y);



See http://pobox.com/~skeet/csharp/events.html for more on this.

I'll now go back and answer the OP's direct questions :)
 
J

Jon Skeet [C# MVP]

Smithers said:
I'm wanting to make sure I have an accurate understanding of the
relationship between delegates and events in .NET.

By "events in .NET" I'm referring to specifically to events defined on the
'event' keyword - not other ways to do events, like old-school callbacks.

Please consider the following event declaration:

line 1: public delegate void SomethingJustHappened(string whatHappened);
line 2: public event SomethingJustHappened MyEvent;

Are the following statements accurate? If any are not, I would appreciate it
if you would briefly explain why it is [they are] inaccurate.

1. line 1 above creates a new type. That type is an extension of
System.Delegate. So, SomethingJustHappened is a System.Delegate.

Well, SomethingJustHappened is a type which derives from
System.MulticastDelegate, yes.
2. The "data type of the event" is SomethingJustHappened (our delegate type
from line 1). [is that how we'd say it - "data type of an event"???]

I'd just say the "type of the event", but your terminology is clear
enough too.
3. Because the event declared in line 2, MyEvent, IS-A
SomethingJustHappened, MyEvent IS-[also]-A System.Delegate. In other words,
event == delegate. Yes?

No. Line 2 actually declares *2* things: a field called MyEvent and an
event called MyEvent. The compiler has turned it into something like
this (leaving out a bit of locking):

private SomethingJustHappened MyEvent; // Field!
public event SomethingJustHappened MyEvent
{
add
{
MyEvent += value; // Use of field!
}
remove
{
MyEvent -= value; // Use of field!
}
}

As you can see, it's pretty confusing having two things with the same
name. Whenever you're in the class, referring to MyEvent will refer to
the field. From outside the class, referring to MyEvent will refer to
the event.

The important thing to take from this is that an event is *just* a pair
of methods which have a particular signature. You can write an event
which ignores the value passed it completely, although it would be
silly to do so. If you use the "full" event syntax (as above), you can
declare the event without also declaring any storage within the class.
4.When we "register a method with an event" we are really registering the
method with the delegate upon which the event is based (or the delegate that
IS ALSO the event).

You're not registering the method with the event. You're registering a
delegate instance which uses that method as its action.

Subscribing to an event involves calling the "add" part of the event
with a delegate instance - that's all. With field-like events, that
delegate instance is then combined with whatever existing event
handlers are involved - but conceptually, you're just calling a method.
5. Conclusion #1 - an event (defined on the 'event keyword') is really a
wrapper for a delegate --- or the event is just *another name* by which we
can refer to the delegate.

An event is just a pair of methods, which often just wrap a delegate.
6. Conclusion #2 - The conceptualization of "event" is little more than a
conceptual convenience for us to think about a specialized use of delegates.
In face, we can substitute delegates in any place where we have an event.

No, in the same way that you can't get rid of properties and just make
fields public. If there's any code doing anything "clever" in
add/remove, exposing the delegate field publicly would have a very
different effect.

The bigger reason for events is encapsulation though. As a consumer of
a button, I shouldn't be able to access its event handlers, or reset
them, or fire them - I should *just* be able to subscribe to and
unsubscribe from the events, and that's what events give you.
I appreciate your time and consideration on this. I'm wanting to understand
what's going on and not "just make it work."

That's the kind of attitude I like to see :)

For more detail on all of this, see
http://pobox.com/~skeet/csharp/events.html
 
S

Smithers

<snip snip snip>
Awesome feedback, as usual, Jon and Peter. Thank you so much.

-S
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top