Popular patterns around events?
In Properties with events: another attempt, Omer said:
I would rather have a protected virtual OnSet method and AfterSet event than just an OnSet event (also consistant with the naming convention ;).
I know understand that this is a common pattern found in .Net, which I didn’t know before.
As you’ve probably noticed in my blogs, I like to take a pattern or guidance and stuff it into a class. My hope is to improve clarity of code & reduce duplication. That’s what I’m trying to do here with events
I read an article at CodeProject, and came up with the code below.
I’ve also read Microsoft’s guidelines, which I conflict with pretty heavily. However, I haven’t yet found a way to reconcile the differences.
(I applied the idea of breaking the class with partial types. Some folks use #region for the same purpose.)
Here’s what I have so far:
// more types
partial class MyEvent
{
// MS guidelines say "Name an event argument class with the EventArgs suffix"
//
// The full name of this type is "MyEvent.Args", which seems to match the
// guidance
public class Args : System.EventArgs
{
public Args(string text) { this.Text = text; }
public readonly string Text;
}
// MS guidelines say "Use an EventHandler suffix on event handler names."
//
// The full name of this type is "MyEvent.Handler", which seems to match
// the guidance.
public delegate void Handler(object sender, Args e);
}
// events
partial class MyEvent
{
// MS guidelines say "Consider naming events with a verb. "
//
// What verb? Or should the class 'MyEvent' be named with
// a verb? Or the instance of the class?
// MS guidelines say "Use a gerund to create an event name that
// expresses the concept of pre-event, and a past-tense verb to represent
// post-event. ... Do not use the BeforeXxx/AfterXxx naming pattern."
//
// But what to call it? Pre and Post?
public event Handler Before = delegate { };
public event Handler After = delegate { };
}
// Overridable methods
partial class MyEvent
{
protected virtual void OnBefore(Args e)
{
this.Before(this, e);
}
protected virtual void OnAfter(Args e)
{
this.After(this, e);
}
}
// Public API
partial class MyEvent
{
Args _e;
public IDisposable Open(Args e)
{
this._e = e;
this.OnBefore(e);
return this;
}
public void Close()
{
this.OnAfter(_e);
this.DebugOnDispose();
}
}
// IDisposable
partial class MyEvent : IDisposable
{
void IDisposable.Dispose()
{
this.Close();
}
}
// DEBUG verification
partial class MyEvent
{
[Conditional("DEBUG")]
void DebugOnDispose()
{
GC.SuppressFinalize(this);
}
// You can't put a Conditional attribute on a destructor!
// [Conditional("DEBUG")]
#if DEBUG
~MyEvent()
{
Debug.Fail("MyEvent was not properly disposed");
}
#endif
}
Edit: Fixed a few bugs in the original code. Todo: Add 'public IDisposable IDisposable { get { return this; } }', and an example of how this class is to be used.
Comments
- Anonymous
July 01, 2004
Shouldn't you start with how to use the class, then code it? - Anonymous
July 01, 2004
I am failing to understand the Open semantics where you return an IDisposable. You have to new a MyEvent class in order to call Open() or did you mean for this to be static?
I haven't looked into partial classes to much yet so this surprised me
partial class MyEvent : IDisposable
Would you then use your own event class in place of the System.Event? I haven't spent any time thinking about it, but what would this do to your usability/interoperability with other areas? - Anonymous
July 01, 2004
Thomas: Many smart people keep saying what you've said, but I just won't listen...
Once I figure out how it should be used, I'll write it down LOL. - Anonymous
July 07, 2004
Comment on using the naming conventions:Should Args not be MyEventArgs - Anonymous
July 08, 2004
Dirc: Perhaps it should be.
The official guidance would have me create a global class called "MyEventArgs". But when I see that name and "MyEvent", I see duplication that I want to remove.
So, I move MyEventArgs to be a nested type inside MyEvent. Now the full name is "MyEvent.Args". That's only one character different than the recommnended name, and it's a very small character indeed!
See also http://blogs.msdn.com/jaybaz_ms/archive/2004/07/02/172144.aspx for an updated version of this class which I like a great deal more.