mucking with Event Definitions to get tighter coupling to Objects ?

B

Bill Woodruff

WinForms app, C#, .Net 2.0, Visual Studio 2005, all the flavors of the
FrameWork (and service packs) installed up to 3.5

Hi,

I assume you're all familiar with the typical way you define an Event using
a Delegate EventHandler, perhaps creating a CustomEventArgs that convey
additional parameters to other Windows Event Handlers or units of code that
register to "receive" the event. Something like "Exhibit A" at the end of
this message. We are all familiar, I think it's fair to say, with the :

object Sender, EventArgsofSomeType e

Parameter requirements. And I would guess we have experience with the often
required casting involved to turn Sender into some type we need to deal
with, or using modified EventArgs to pass instances of whatever types.

As an experiment I have modified the whole nature of an EventHandler, done
away with "object sender" and "EventArgsofSomeTyp e," and in essence
"tightly bound " the code to existing objects I know are persistent in my
application. See Exhibit B attached below.

Using the techniques shown in "Exhibit B" I eliminate any need for casting
by the subscribers to the event (as long as they have the reference to the
type of the passed object). I still get the += facility "kicking in" in the
IDE with auto-complete for this modded Event code.

And comparing one instance implemented with techniques in Ex. A with another
instance implemented with techniques in Ex. B : seem to get the same
run-time functionality.

Each of the "exhibits" is in the context of a run-time created Form which
does not have its parent property set to the MainAppForm. Each run-time
created Form is instanced from a configured Form Template which contains a
single button. When that button is clicked the Click Event Handler calls
OnIndependentMessage1 : in exhibit A as you can see passing an object and a
custom EventArgs; in exhibit B passing only the pointer to the current
executing run-time form on which the button click has occurred.

My questions :

1. is what I am doing flat-out wrong/bad/blasphemy/poor coding in your
opinion ?

2. what issues could arise from not following the standard .NET event
Sender, EventArgs parameter order structure. I'm assuming there are issues
other than the developer has to carry a slightly more "heavy" weight mental
model.

3. if you would use a technique like this, in what scenarios would you use
it and why.

4. could this technique, by eliminating casts and lookups contribute any
real increase in speed or whatever in apps ? In other words, given you Can
use it, is it worth using ?

many thanks for your examining and commenting on this. the code has
unusually long verbose variable names because I am writing it as an
educational tool to demonstrate an alternate way to Raise Events ... even if
using the technique is not a "good thing" I think it will have educational
value as a way to focus in on exactly how the Event raising is done now by
contrasting its dynamic behavior and structure with the existing model.

"Escapee from the Island of Dr. Moreau" ?, hack ?, possibly useful ? You are
the judge.

best, Bill Woodruff
dotScience
Chiang Mai, Thailand


// Exhibit A ... from working code ...

#region 'IndependentWindowMessage1' event definition code

// Delegate method prototype that event receivers must implement

public delegate void
IndependentWindowMessage1EventHandler(SecondaryIndependentWindow
theIWindow);

// Private delegate linked list (explicitly defined)
private IndependentWindowMessage1EventHandler
IndependentWindowMessage1EventHandlerDelegate;

// Main event definition
public event IndependentWindowMessage1EventHandler IndependentEvent1
{
// Explicit event definition with accessor methods
add
{
IndependentWindowMessage1EventHandlerDelegate =
(IndependentWindowMessage1EventHandler)Delegate.Combine(IndependentWindowMessage1EventHandlerDelegate,
value);
}
remove
{
IndependentWindowMessage1EventHandlerDelegate =
(IndependentWindowMessage1EventHandler)Delegate.Remove(IndependentWindowMessage1EventHandlerDelegate,
value);
}
}

// This is the method that is responsible for notifying
// receivers that the event occurred
protected virtual void OnIndependentMessage1(SecondaryIndependentWindow
theIWindow)
{
if (IndependentWindowMessage1EventHandlerDelegate != null)
{
IndependentWindowMessage1EventHandlerDelegate(theIWindow);
}
}
#endregion //('IndependentEvent1' event definition code)

private void btn_IndependentWindowSendMessage_Click(object sender,
EventArgs e)
{
OnIndependentMessage1(this);
}

Exhibit B ... from working code ... created by modifying Exhibit A code ...

#region 'IndependentWindowMessage1' event definition code

// Delegate method prototype that event receivers must implement
public delegate void
IndependentWindowMessage1EventHandler(SecondaryIndependentWindow
theIWindow);

// Private delegate linked list (explicitly defined)
private IndependentWindowMessage1EventHandler
IndependentWindowMessage1EventHandlerDelegate;

// Main event definition
public event IndependentWindowMessage1EventHandler IndependentEvent1
{
// Explicit event definition with accessor methods
add
{
IndependentWindowMessage1EventHandlerDelegate =
(IndependentWindowMessage1EventHandler)Delegate.Combine(IndependentWindowMessage1EventHandlerDelegate,
value);
}
remove
{
IndependentWindowMessage1EventHandlerDelegate =
(IndependentWindowMessage1EventHandler)Delegate.Remove(IndependentWindowMessage1EventHandlerDelegate,
value);
}
}

// This is the method that is responsible for notifying
// receivers that the event occurred
protected virtual void
OnIndependentMessage1(SecondaryIndependentWindow theIWindow)
{
if (IndependentWindowMessage1EventHandlerDelegate != null)
{
IndependentWindowMessage1EventHandlerDelegate(theIWindow);
}
}

#endregion //('IndependentEvent1' event definition code)

private void btn_IndependentWindowSendMessage_Click(object sender,
EventArgs e)
{
OnIndependentMessage1(this);
}
 
M

Marc Gravell

Re the event combine/remove, you can probably just use += and -= like
normal; likewise, you can probably work with an auto-implemented event
(since you aren't doing anything special); this doesn't demand the
"sender, args" pattern.

I think the biggest problem here is re-use; for example, thinking
about an example like MouseEventHandler, this can be used and thrown
by a whole *host* of senders. If you don't want an "object sender",
then you'd either need lots of delegates, or generics; perhaps
extending the existing EventHandler<T> with something like:

public delegate void EventHandler<TSender, TArgs>
(TSender sender, TArgs args)
where TSender : class
where TArgs : EventArgs;

However, I'm not sure it is worth the extra complexity. The designer
probably won't like it much either, and it loses the faint traces of
co[ntra]varaiance [I always get confused over which] that delegates
offer.

In most cases, without a very good reason, I'd stick the the standard
pattern. Although I have done something "other" recently, it wasn't
typical notification events, but something else; that's my excuse and
I'm sticking to it...

Marc
 
P

Peter Duniho

[...]
1. is what I am doing flat-out wrong/bad/blasphemy/poor coding in your
opinion ?

No, I wouldn't say so.
2. what issues could arise from not following the standard .NET event
Sender, EventArgs parameter order structure. I'm assuming there are
issues
other than the developer has to carry a slightly more "heavy" weight
mental
model.

The primary issue I see is the one that motivates the .NET convention: if
you make the event delegate signature dependent on the class implementing
the event, then you cannot write a handler that is compatible with
multiple classes, generally speaking. One exception is if the event is
declared in a base class, then of course you could have a single event
handler method handle the same event for multiple derived classes.

This doesn't come up a lot, but it can. If it's of no concern to you,
then I wouldn't worry about it too much.

The other issue is of course adhering to existing conventions. This is
not one I personally worry too much about, but I know that others do and I
don't fault them for it. This isn't a code-correctness issue so much as
it is a potential maintenance and multi-person team issue. Having the
exact same signature pattern for all events is helpful in making the code
readable, because you can always look at a method and see right away that
it's an event handler. That said, there are other clues in the method
signature (for example, if the first parameter is always named "sender"
and the second parameter's type always has the phrase "EventArgs" in it,
then that's at least as powerful a clue).
3. if you would use a technique like this, in what scenarios would you
use
it and why.

I can't think of any in which I'd specifically bother. That said, I'm
sure that at least once I've written an event that doesn't share _any_ of
the .NET convention (e.g. may not even include a sender or event data).
It can be done, and if you feel it's important enough to do so, then don't
let the convention stand in your way.
4. could this technique, by eliminating casts and lookups contribute any
real increase in speed or whatever in apps ? In other words, given you
Can
use it, is it worth using ?

Not from a performance point of view, no. If your code's performance is
bottlenecked by a cast, then it is already doing basically nothing and
should be able to do that nothing extremely quickly. :)
many thanks for your examining and commenting on this. the code has
unusually long verbose variable names because I am writing it as an
educational tool to demonstrate an alternate way to Raise Events ...

I didn't even bother to look closely at the code. For what it's worth, if
you're asking a question, post code that someone will actually read, and
which includes _only_ the bare minimum required. In this particular
instance, you could have simply posted the .NET convention, and an example
of the delegate type for a non-compliant event. There was no need to post
all that other stuff, and the more complex the code you post, the more
likely someone will not read it, or will even ignore your entire post.

Pete
 
B

Bill Woodruff

Peter Duniho wrote :

<intro : specific responses to your comments follow this generic response
.... >

.... thanks Peter for taking the time to ponder seriously this somewhat outre
thought experiment ! fyi : I have extended this one step further to address
the issue of code maintenance and clarity (I hope) by defining a static
class called "CustomEvents : I now include each Custom Event definition as a
static class within 'CustomEvents. The decision to implement the container
class and its nested inner Event classes as static was done more just to see
"if I could get away with it" rather than on any deep strategy. And I was
damn surprised it worked immediately

Next step would be for me to see if I can define a base static class that
CustomEvents would inherit from to isolate certain common features shared by
all CustomEvents and abstract the code a bit further. And then to look at
using a non-static class container, within which the contained Event
definitions could also be non-static. For me I look at this kind of
experimentation as being like seeking to understand the "standard model" in
physics by examining black holes and other variant phenomena :) It's long
range value may be nil, or may be, I hope, a more solid grounding for myself
in understanding the "standard model." And then the obvious next step is to
see if I can refactor the Events based on some common feature they share (or
focus on combining Events by just having them all pass the pointer to their
originating WinForm context, with more "work" being done in the Controller
to pull out from the passed WinForm pointer data of interest.

The "bigger picture" for me here is the context of implementing an MVC model
window manager where there is one MainForm, and an arbitrary of secondary
windows (with Parent == null) created at run-time by the end user. The
end-user will have the choice to create several kinds of secondary windows
using pre-defined WinForm templates; some of those Windows could contain
data-bound controls. So, imho, potentially, in trying to strive to have the
"Controller" robust (must listen for and handle many different types of
Events being raised as needed by the secondary windows), as well as maintain
state lists of all current Windows updated as they possibly "wink and blink
out of existence" or "pop into being," I see a potential need for some
custom events.

2. what issues could arise from not following the standard .NET event
Sender, EventArgs parameter order structure.

PD : "The primary issue I see is the one that motivates the .NET convention:
if
you make the event delegate signature dependent on the class implementing
the event, then you cannot write a handler that is compatible with
multiple classes, generally speaking. One exception is if the event is
declared in a base class, then of course you could have a single event
handler method handle the same event for multiple derived classes."

I see your point. In this case I was thinking about a future scenario in
which derived types would inherit ... a point you raise in your response.
This is more a "gedanken," a thought experiment for self-educational
purposes (I hope for other developers also when I finish an article in which
I will use this to illustrate, by contrast, how the "standard model" is
structured and operates.

PD : "The other issue is of course adhering to existing conventions. This
is
not one I personally worry too much about, but I know that others do and I
don't fault them for it. This isn't a code-correctness issue so much as
it is a potential maintenance and multi-person team issue."

Indeed. The risks of unconventional code for maintenance and team
collaboration would be a number one "real world" consideration.
4. could this technique, by eliminating casts and lookups contribute any
real increase in speed or whatever in apps ? In other words, given you
Can use it, is it worth using ?

PD : "Not from a performance point of view, no. If your code's performance
is
bottlenecked by a cast, then it is already doing basically nothing and
should be able to do that nothing extremely quickly. :)"

Point well taken. Being an old dinosaur who comes from the Pleistocene where
every byte counted, :) I am always scanning for ways to reduce look-ups and
casts. Perhaps now that we wallow in gigabytes of ram and blazing cpu's
that's an antediliuvian habit that I can kick :)

PD : "if you're asking a question, post code that someone will actually
read, and
which includes _only_ the bare minimum required. ...There was no need to
post
all that other stuff, and the more complex the code you post, the more
likely someone will not read it, or will even ignore your entire post."

Good point ! The judgement call I made to include more elaborate code here
was based on the idea that I wanted to make it a little more than abstract
since I was discussing a variant from standard practice (and also on the
asummption that the folks here can look at more complete code quickly and
see exactly where and how the variance from the "standard model" occurs).
With hindsight, I think you are right, I could have could have cut the
included way down. It being a long, long day and night of sweating over code
is no excuse :)

thanks, Bill Woodruff
dotScience
Chiang Mai, Thailand
 
B

Bill Woodruff

Marc Gravell wrote :

"Re the event combine/remove, you can probably just use += and -= like
normal; likewise, you can probably work with an auto-implemented event
(since you aren't doing anything special); this doesn't demand the
"sender, args" pattern."

Hi Mark, yes, you can. And if I couldn't do that, I wouldn't have pursued
this further than an initial look-see. It's just too convenient a feature to
bypass.

"I think the biggest problem here is re-use; for example, thinking
about an example like MouseEventHandler, this can be used and thrown
by a whole *host* of senders. If you don't want an "object sender",
then you'd either need lots of delegates, or generics; perhaps
extending the existing EventHandler<T> with something like:

public delegate void EventHandler<TSender, TArgs>
(TSender sender, TArgs args)
where TSender : class
where TArgs : EventArgs;"

Agreed, code-re-use and maintenance are paramount criteria; this is more a
"thought experiment" right now, although I am now less sceptical than I was
at the beginning that it might be of sheerly academic value. Thanks for your
"generic flavor" example; I am going to think carefully about this and play
with it ! Me like generics.

"However, I'm not sure it is worth the extra complexity. The designer
probably won't like it much either, and it loses the faint traces of
co[ntra]varaiance [I always get confused over which] that delegates
offer."

Good point, I have not yet given thought to other designers who might be
"consumers" of the source code; only thought about internal code
optimization which would be "opaque" to end-users of a run-time application.

"In most cases, without a very good reason, I'd stick the the standard
pattern. Although I have done something "other" recently, it wasn't
typical notification events, but something else; that's my excuse and
I'm sticking to it..."

If you care to read my responses to Peter Duniho in this thread, I say more
about what this "thought experiment" represents to me.

And I sure am not on a "mission" to promote some variant esoteric philosophy
of Event Handling. We light candles for Anders Hejlsberg and the other
".NET" saints around here :) What fascinates me is how flexible the
facilities in .NET are to go "beyond" standard practices. The goal here is
knowledge for its own sake, but I admit to having an intuition that there
could be a certain type of application scenario (involving very complex
interactions in an MVC model between Controller and multiple secondary
Views) in which this type of variant Event handling could actually be
valuable.

Thanks for your time in responding !

best, Bill Woodruff
 
J

Jordan S.

You might do well to consider the maintenance burden and learning curve you
are creating for anyone who has no idea how your custom event model works.

As complex as your model is apparently getting throughout the day [today]
with your base classes and whatnot, you are also creating a
solution-specific implementation of your event model. At least that's the
case unless you refactor it out into some plug-in architecture or such
whereby you have a library that you can drop into any project and your
custom event stuff is all ready to "just use."

Maybe I'm wrong, but based on what you are writing, it seems to be getting
less and less like an academic exercise whereby you are gaining some
"appreciation" for the standard way to do things. Maybe I'm missing
something. Have you gained any new appreciation for the "object sender
EventArgs e" standard? Or do you like it less and less as you evolve your
ideas. Maybe you could share with us, briefly, what you have concluded to be
the important trade-offs between the standard and your own model.

-J
 
B

Bill Woodruff

"You might do well to consider the maintenance burden and learning curve you
are creating for anyone who has no idea how your custom event model works."

I wouldn't call what I am doing a "model" right now; I am just creating some
legitimate (in the sense of they will compile and work) variations in the
typical use of the Events "standard model" and thinking, studying, what
might be the costs/benefits/gotchas of using those variations.

"As complex as your model is apparently getting throughout the day [today]
with your base classes and whatnot,"

I wouldn't call it growing in complexity. Probably I'm just making it sound
more complex than it is. Separating out Event definitions which are common
to many run-time created windows (not specific to specific windows) into a
Class of their own to me results in more readable and more maintainable
code. For me the required discipline of writing static Classes seems to make
me pay more attention to the way I code :

being static means never being born new :)

and I like the idea that something meant to be defined once and only once (a
mini-singleton ?) should be ... defined ... only once : which writing as
static forces me to do. Similarly use of Interfaces that inherit from
Interfaces judiciously to me is a small task compared to the benefits of
knowing immediately (because they won't compile if they don't) that my
Classes that inherit from those Interfaces comply with the Interface
contract (casting to Interfaces, another story ... for me, so far).

"you are also creating a solution-specific implementation of your event
model. At least that's the case unless you refactor it out into some plug-in
architecture or such whereby you have a library that you can drop into any
project and your custom event stuff is all ready to "just use.""

I would disagree with you there. I can see what I am doing now as
establishing a basic MVC application template I will use from now on in any
WinForms project I do where multiple secondary windows Forms (Parent ==
null) are created at run-time, based on an end-user's selection of what
pre-defined Window Template to use. And those are the kinds of projects I
do. Within that larger meta-project (based on my unhappiness with the
"standard models" of SDI and MDI window management) this excursion into
Event handling has an organic role.

Long before I ever heard about MVC, maybe the late 1980's (? ... yeah, I'm
that antiquated :), I was talking about "one data many views," and that's
been a "Grail Quest" for me ever since.

"Maybe I'm wrong, but based on what you are writing, it seems to be getting
less and less like an academic exercise whereby you are gaining some
"appreciation" for the standard way to do things."

My honest assessment is I yet don't know the outcome of this "thought
experiment." For me doing these kinds of things pay off, most of the time.

"Maybe I'm missing something. Have you gained any new appreciation for the
"object sender
EventArgs e" standard? Or do you like it less and less as you evolve your
ideas. Maybe you could share with us, briefly, what you have concluded to be
the important trade-offs between the standard and your own model."

I'd distinguish between endorsing the concept of event multi-casting
fervently, and mixed feelings about the sender-e syntax of the
implementation of that paradigm. That may change.

If I reach the point I have something which I feel other developers can
benefit from, certainly I'll publish ! This is about sharing, to me.

I do appreciate your comments, they seem constructively challenging to me.

best, Bill
 
B

Ben Voigt [C++ MVP]

4. could this technique, by eliminating casts and lookups contribute any
Not from a performance point of view, no. If your code's performance is
bottlenecked by a cast, then it is already doing basically nothing and
should be able to do that nothing extremely quickly. :)

True, the primary penalty for using casts is not finding errors until
runtime.
 

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