Property accessors "add" and "remove" with event properties andEventHandlerList

F

FullBandwidth

I have been perusing various blogs and MSDN pages discussing the use
of event properties and the EventHandlerList class. I don't believe
there's anything special about the EventHandlerList class in this
context, in fact some articles from pre-2.0 suggest using any
collection class of your choice. So my questions focus more on the
syntax of event properties provided by the "event" keyword in C#.
(Disclaimer - I am a C++ programmer working on a C# development
project, so I tend to think in C++ and try and translate it in to C#.)

Are the "add" and "remove" properties of an event declaration defined
in a class somewhere, or are they part of the C# language definition?
Are there any other properties? Where are any of these documented?.

I also assume that the compelling reason to use event properties
defined this way is to allow event consumers to use += and -= to
subscribe and unsubscribe to events.

Every C# example I see has a very VB5-centric flavor to it -
specifically, each event must have a unique name defined in the source
code. For instance, here's the code segment from the MSDN article "How
to: Handle Multiple Events Using Event Properties"

// Define the delegate collection.
protected EventHandlerList listEventDelegates = new
EventHandlerList();

// Define a unique key for each event.
static readonly object mouseDownEventKey = new object();
static readonly object mouseUpEventKey = new object();

// Define the MouseDown event property.
public event MouseEventHandler MouseDown {
// Add the input delegate to the collection.
add { listEventDelegates.AddHandler(mouseDownEventKey, value); }
// Remove the input delegate from the collection.
remove { listEventDelegates.RemoveHandler(mouseDownEventKey,
value); }
}

// Define the MouseUp event property.
public event MouseEventHandler MouseUp {
// Add the input delegate to the collection.
add { listEventDelegates.AddHandler(mouseUpEventKey, value); }
// Remove the input delegate from the collection.
remove { listEventDelegates.RemoveHandler(mouseUpEventKey,
value); }
}

Any time I see code cut-and-pasted like this is a red flag that a
proper object-oriented decomposition of the problem hasn't been
performed. There are two events declared by name (MouseDown and
MouseUp) and yet the code that implements their properties "add" and
"remove" are nearly identical, except for the "key" argument (an
arbitrary static value, to provide a unique key for the
EventHandlerList class).

If the "key" argument could somehow be available to the add and remove
properties, this whole thing could be implemented as a class, and the
events, instead of having to be individually named at compile time,
could be part of a collection of objects of that class. However, the
"add" and "remove" properties seem to be a "hardcoded" notion in the
C# language, with the keyword "value" the only argument available to
the implementation of those properties (in this case, "value" is of
type Delegate). Am I misunderstanding this?

I have also read posts here that suggest "event" is syntactic sugar
such that the C# compiler will automatically generate the property
accessor functions, so that clients can use the += and -=.

If I wanted to ditch this notion that every event has to have a name
defined at compile time, I can think of how to implement such a class
hierarchy. However, I'm not sure if can override the += and -=
operators in my homegrown event properties implementation - would this
be possible?

Thanks
 
J

Jon Skeet [C# MVP]

FullBandwidth said:
I have been perusing various blogs and MSDN pages discussing the use
of event properties and the EventHandlerList class. I don't believe
there's anything special about the EventHandlerList class in this
context, in fact some articles from pre-2.0 suggest using any
collection class of your choice. So my questions focus more on the
syntax of event properties provided by the "event" keyword in C#.
(Disclaimer - I am a C++ programmer working on a C# development
project, so I tend to think in C++ and try and translate it in to C#.)

Are the "add" and "remove" properties of an event declaration defined
in a class somewhere, or are they part of the C# language definition?

They're part of the C# language specification, and also the CLI spec.
Are there any other properties? Where are any of these documented?.

They aren't properties. They're operations on the event. They're
similar to the "get" and "set" part of real properties, with the
difference that you can't declare an event with an "add" but not a
"remove" (or vice versa).

IIRC, the CLI spec includes another associated method: "raise" which C#
neither generates nor refers to.
I also assume that the compelling reason to use event properties
defined this way is to allow event consumers to use += and -= to
subscribe and unsubscribe to events.

Yes, it's encapsulation. It allows the class to advertise an event in a
subscribe/unsubscribe manner, but internally keep it in whatever
implementation it wants.
Every C# example I see has a very VB5-centric flavor to it -
specifically, each event must have a unique name defined in the source
code.

I don't see why that's VB5-centric. If each event doesn't have a unique
name, how could it be resolved at compile-time in a statically typed
manner?
For instance, here's the code segment from the MSDN article "How
to: Handle Multiple Events Using Event Properties"

Any time I see code cut-and-pasted like this is a red flag that a
proper object-oriented decomposition of the problem hasn't been
performed. There are two events declared by name (MouseDown and
MouseUp) and yet the code that implements their properties "add" and
"remove" are nearly identical, except for the "key" argument (an
arbitrary static value, to provide a unique key for the
EventHandlerList class).

Do you think there's a "red flag" every time you see a property
declared which just reads/writes from/to a variable? That's just cut-
and-paste code using different variables each time, too. It's not like
there's significant logic being duplicated.
If the "key" argument could somehow be available to the add and remove
properties, this whole thing could be implemented as a class, and the
events, instead of having to be individually named at compile time,
could be part of a collection of objects of that class. However, the
"add" and "remove" properties seem to be a "hardcoded" notion in the
C# language, with the keyword "value" the only argument available to
the implementation of those properties (in this case, "value" is of
type Delegate). Am I misunderstanding this?

I think you're misunderstanding the real nature of an event. An event
is like a property - it has two associated methods with it, for
callers. It's not that add and remove are properties *of* the event.
They're just methods associated with it.
I have also read posts here that suggest "event" is syntactic sugar
such that the C# compiler will automatically generate the property
accessor functions, so that clients can use the += and -=.

The compiler will automatically generate the add/remove if you use a
field-like event, which is where you just write something like:

public event EventHandler Click;

That will create an event called Click and a hidden variable of type
EventHandler. The variable is private - whenever you refer to "Click"
from within the class, that refers to the variable; whenever you refer
to "Click" from outside the class, that refers to the event. The
add/remove which are automatically generated are effectively:

add
{
lock(this)
{
compiler_generated_click_variable += value;
}
}
remove
{
lock(this)
{
compiler_generated_click_variable -= value;
}
}
If I wanted to ditch this notion that every event has to have a name
defined at compile time, I can think of how to implement such a class
hierarchy. However, I'm not sure if can override the += and -=
operators in my homegrown event properties implementation - would this
be possible?

If you didn't have names defined at compile-time, += and -= don't make
any sense anyway as far as I can see.

You could of course write two methods:

public void AddHandler(string eventName, EventHandler handler)
public void RemoveHandler(string eventName, EventHandler handler)

But you'd lose all the compile-time safety, relying on magic names
instead. (You could use an enum instead, of course, but it's still not
ideal.)

Personally I'd stick with the idiomatic .NET solution. If other people
use your API, they're unlikely to want to learn another eventing
mechanism.
 
M

Marc Gravell

There is another reason to stick with the trend; it is what other
framework code expects [your code isn't the only thing that attaches
to events].

For example, data-binding supports 2 patterns; one of these is the
"property Foo, event FooChanged" pair, which PropertyDescriptor will
recognise and expose via SupportsChangeEvents, AddValueChanged and
RemoveValueChanged. This will only work if your event uses the regular
event pattern. Note, however, then the encapsulated implementation is
not an issue - inside the event it could use a delegate field (either
explicit or implicit from the abbreviated event syntax), or it could
use EventHandlerList, etc.

Another example here would be the IDE; the IDE has fairly good support
for events. With an alternative strategy, some of this would
undoubtably be lost.

Marc
 
F

FullBandwidth

Guys, thanks for the comments, I am grateful for your insights. A
couple of go-backs, if you're willing to follow up:

I don't see why that's VB5-centric. If eacheventdoesn't have a unique
name, how could it be resolved at compile-time in a statically typed
manner?
"VB5-centric" meaning "resistant to implementation as a factory (or
other pattern)," I guess is what I was trying to say. It seems like
VB4, VB5, VB6 etc. crawled along the path towards Booch-style OO that
Smalltalk, C++, Java, and C# always had built-in. So it was an
inflammatory dig, to some extent, but I didn't figure there'd be too
many VB apologists on this newsgroup ;)

Maybe I haven't thought through it enough (or am still too mired in
the C/C++ notion of collections of function pointers), but I still
don't see why event delcarations need to be available at compile-time
by individual names, versus a collection of appropriately (statically)
typed objects that could be manipulated at run time.
Do you think there's a "red flag" every time you see a property
declared which just reads/writes from/to a variable? That's just cut-
and-paste code using different variables each time, too. It's not like
there's significant logic being duplicated.
Y'know, now that you mention it... but that's a topic for another
thread...
I think you're misunderstanding the real nature of anevent. Anevent
is like a property - it has two associated methods with it, for
callers. It's not that add and remove areproperties*of* theevent.
They're just methods associated with it.
Meaning, the real nature of an event as currently implemented in C#.
Maybe not the implementation I would have preferred, but at least I
understand now what that implementation is.

If you didn't have names defined at compile-time, += and -= don't make
any sense anyway as far as I can see.
The RHS of such an expression would be an element from the collection
of delegates - indexed by a unique key, something like what you've
expressed below:
You could of course write two methods:

public void AddHandler(string eventName, EventHandler handler)
public void RemoveHandler(string eventName, EventHandler handler)

But you'd lose all the compile-time safety, relying on magic names
instead. (You could use an enum instead, of course, but it's still not
ideal.)
Actually the motive behind these questions is that I am trying to brew
up a more complete "event properties" example, one that includes both
the Observer pattern and the Chain of Command pattern. The comments
you guys provided have gotten me closer to that; I hope to post it
here and get some critiques on it. The example I have now uses
typeof() and a class hierarchy (vs. magic names or enums). I realize
that doesn't make much sense out of context, but maybe it will when I
post the example.
Personally I'd stick with the idiomatic .NET solution. If other people
use your API, they're unlikely to want to learn another eventing
mechanism.
There is another reason to stick with the trend; it is what other
framework code expects [your code isn't the only thing that attaches
to events].

Quite true - really what I was trying to find out exactly what the
extent of that idiom is. That way, this thorough example I'm trying to
come up with is recognizeable as consistent with the idiom.


Thanks again.
 
J

Jon Skeet [C# MVP]

"VB5-centric" meaning "resistant to implementation as a factory (or
other pattern)," I guess is what I was trying to say. It seems like
VB4, VB5, VB6 etc. crawled along the path towards Booch-style OO that
Smalltalk, C++, Java, and C# always had built-in. So it was an
inflammatory dig, to some extent, but I didn't figure there'd be too
many VB apologists on this newsgroup ;)

Maybe I haven't thought through it enough (or am still too mired in
the C/C++ notion of collections of function pointers), but I still
don't see why event delcarations need to be available at compile-time
by individual names, versus a collection of appropriately (statically)
typed objects that could be manipulated at run time.

How would you wish to subscribe to, say, the "Click" event of
something instead of the "DoubleClick" event? You could have a
collection with some sort of enum key - but then you'd need to
associate the type of each event with its key as well. While this
could be done with sufficient language support I don't think it would
add much over the current way of doing things.

It's also helpful to have the set of events associated with a type
discoverable via reflection - there would need to be support for this
in some form or other for designers etc.
Meaning, the real nature of an event as currently implemented in C#.
Maybe not the implementation I would have preferred, but at least I
understand now what that implementation is.

No, it's not C# - it's .NET. An event in .NET has those aspects of
metadata (and another optional one for raising the event, IIRC, which
C# ignores). You're right that it's technology-specific terminology,
but it's not C#-specific.
The RHS of such an expression would be an element from the collection
of delegates - indexed by a unique key, something like what you've
expressed below:

Okay, so we'd need different language features to safely have the keys
and associated types. We'd also end up defining a new collection of
event keys (probably a new type) every time we wanted to implement an
event. The common implementation of events isn't to use EventList to
start with, unless you've got a lot of events which are likely to be
sparsely populated.

While I can see merit in avoiding the repetition, I think the current
idiom works pretty well and the *practical* issues with the repetition
are minimal in my experience.
Actually the motive behind these questions is that I am trying to brew
up a more complete "event properties" example, one that includes both
the Observer pattern and the Chain of Command pattern. The comments
you guys provided have gotten me closer to that; I hope to post it
here and get some critiques on it. The example I have now uses
typeof() and a class hierarchy (vs. magic names or enums). I realize
that doesn't make much sense out of context, but maybe it will when I
post the example.

Using typeof() and class hierarchies doesn't immediately sound nice, I
have to say. There are alternatives for "smart enums", although they
don't have much language support. When I've seen your code I may be
able to suggest some of them :)
Personally I'd stick with the idiomatic .NET solution. If other people
use your API, they're unlikely to want to learn another eventing
mechanism.
There is another reason to stick with the trend; it is what other
framework code expects [your code isn't the only thing that attaches
to events].

Quite true - really what I was trying to find out exactly what the
extent of that idiom is. That way, this thorough example I'm trying to
come up with is recognizeable as consistent with the idiom.

Thanks again.

No problem. I'll look forward to seeing your code, although I'm still
somewhat doubtful that I'll be won over ;)

Jon
 

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