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.