If I have ClassA that has a public event, SomeEvent, and ClassC that has method, addListener, that accepts an EventHandler reference, why can’t ClassB have a line that says c.addListener(ref a.SomeEvent)? If I try I get a compiler error that says: “The event ‘ClassA.SomeEvent’ can only appear on the left hand side of += or -= (except when used from within the type ‘ClassA’).
Why does this restriction exist? And how can I get around it while staying reasonably close to my structure?
I’m a C# newbie; any help would be appreciated. Thanks!
class ClassA {
public event EventHandler SomeEvent;
}
ClassB{
public ClassB() {
ClassA a = new ClassA();
ClassC c = new ClassC();
c.addListener(ref a.SomeEvent); //Compile error
}
}
class ClassC {
public void addListener(ref EventHandler handler) {
handler += onEvent;
}
private void onEvent(object sender, EventArgs e) {
//do stuff
}
}
The event keyword creates an accessor for a private delegate object. The exact same thing a property does, it restricts access to a private field. Your code snippet fails with a similar kind of error when you use a property instead of an event:
It is easier to see now, there is no way for the compiler to ensure that the setValue() method uses the property setter. Nor could it know that the “value” argument is a property with a setter or a plain field.
It is less clear for an event because there is so much syntax sugar at work. This declaration
actually generates this code:
The add and remove accessors are equivalent to the get and set accessors of a property, they prevent code from messing with the private _SomeEvent field. By convention, the add accessor is invoked when you use +=, remove is invoked with -=. Compare this with the earlier example I gave for a property. Same problem, you can’t use the ref keyword and ClassC.addListener() would have no way to know that the handler is actually an event instead of a delegate object. If the compiler would pass _SomeEvent instead, the point of using the accessors is lost.
You can restructure the code to solve this problem:
One final note: the symmetry between an event and a property is a bit lost, the C# compiler automatically generates the add/remove accessors if you don’t write them explicitly. It doesn’t do this for a property. It would have made automatic properties a lot easier:
But that would have required adding a new keyword to the language, something the C# team really dislikes. Other languages like VB.NET and C++/CLI do have that keyword.