I have a class library containing a number of classes, and in each class I raise a number of events.
Each event has its own set of event arguments, so I store these as automatic properties in classes inheriting from EventArgs. I can then raise the relevant event by simply calling Invoke and passing in a new instance of my EventArgs inherited class. This is what I mean:
using System;
//My Class Library
namespace MyClassLibrary
{
//A class
public class MyClass
{
//My event is a field
public event EventHandler<MyEventHandler> myEvent;
//I raise my event in this method
public void InvokeMyEvent()
{
//Do some stuff
//I raise my event here
myEvent.Invoke(this, new MyEventHandler("The quick brown fox jumps over the lazy dog"));
//Do some more stuff
}
}
//An event handler, containing some interesting data about the event
public class MyEventHandler : EventArgs
{
//Some interesting data as an automatic property
public string MyInterestingData { get; private set; }
//I assign the value of my intersting data in my constructor
public MyEventHandler(string FooBar)
{
MyInterestingData = FooBar;
}
}
}
So this is what I want to do. Now, in my application, I can add a reference to my class library, instantiate MyClass and subscribe to my event like so. The great thing about this (using a generic event handler) is that Intellisense allows me to use the Tab key when subscribing to my event, and sets up the method for me, passing in MyEventHandler as default. No casting neccessary.
using System;
using MyClassLibrary;
namespace ConsoleApplication33
{
class Program
{
static void Main(string[] args)
{
MyClass x = new MyClass();
x.myEvent += new EventHandler<MyEventHandler>(x_myEvent);
}
static void x_myEvent(object sender, MyEventHandler e)
{
//Doing lots of important stuff
//Able to access my interesting data in my event handler without casting
var y = e.MyInterestingData;
}
}
}
This all compiles fine, but the point of a class library is surely to have a bank of re-usable code, which is certainly the intention here. So I want to add my class library to a number of projects. In some of these projects, It will be neccessary for my to subscribe to myEvent, in others it won’t, but I still want to use other features of the class in these projects, and have the option to subscribe to myEvent in the future.
However, if I am using my class library in a project in which I don’t subscribe to myEvent, I get a Runtime error whenever myEvent is raised.
I have gotten around this by subscribing to myEvent in the constructor of MyClass with an empty method like so:
public MyClass()
{
myEvent += new EventHandler<MyEventHandler>(MyClass_myEvent);
}
void MyClass_myEvent(object sender, MyEventHandler e)
{
}
This means that I can add my class library to any project, instantiate MyClass and use away at the other functionality it provides, and subscribe to myEvent if I need to, while ignoring myEvent if I don’t.
The problem with this is that I have an empty method in MyClass. Imagine this scenario but with about 30 events, and therefore 30 empty methods.
A couple of questions
- Am I making sense? As in do you at least understand what I am trying to do, even if you think I am going about this all wrong?
- Is there actually a problem here, or is this a fairly standard way of going about achieving the functionality I am trying to achieve?
Thanks
This is usually why you see the following pattern with events:
The event will be null if it has no subscribers. This code takes a local copy to ensure that the event at point of check is not involved in a race condition. The copy is then invoked. Even though this guards against a race condition in one form, the original subscriber list could still undergo changes, which won’t be visible in your copy, so it isn’t entirely thread-safe.
To be honest, I’ve never considered, or even seen, doing it the way you have. I say it’s best to stick with the null check as opposed to an empty method subscriber, people expect the former, not the latter.
Also, the empty method route costs memory / objects where the null route only costs a check.
Just as an aside, the
MyEventHandlerarguments class is usually called something likeMyEventArgs.