Geeks With Blogs
Running with Code Like scissors, only more dangerous

One of the more obscure features of C# is the ability to specify custom overloads for adding and removing event registration similarly to properties, via the add and remove keywords.  Known as "event accessors," they implement the parts of event registration that the C# compiler normally handles.  You didn't think that that += operator was implemented on the type, did you?

   1:  class Test
   2:  {
   3:      public event EventHandler Event1;
   5:      private EventHandler ev2;
   6:      public event EventHandler Event2
   7:      {
   8:          add
   9:          {
  10:              if (ev2 != null)
  11:                  ev2 = (EventHandler)Delegate.Combine(ev2, value);
  12:              else
  13:                  ev2 = value;
  14:          }
  15:          remove
  16:          {
  17:              if (ev2 != null)
  18:                  ev2 = (EventHandler)Delegate.Remove(ev2, value);
  19:          }
  20:      }
  21:      protected virtual void OnEvent2(EventArgs e)
  22:      {
  23:          if (ev2 != null)
  24:              ev2(this, e);
  25:      }
  26:  }

This pattern is actually used extensively throughout the Windows Forms library, where controls add event handlers to base event handler collections implemented within a hashtable.  I can only surmise that this is done to prevent having dozens of event fields cluttering up the classes.

Now, if we were to compile this app and disassemble it in Reflector, we'd get a very similar picture to what we've got.  Reflector would show the compiler-generated add/remove blocks for Event1, though not when the event declaration is selected, and it also indicates that there are compiler directives that show the event accessors are synchronized.

Visual Basic .NET also supports this pattern, but adds an additional keyword: the RaiseEvent keyword:

   1:  Public Class Test
   2:      Public Event Event1 As EventHandler
   4:      Private ev2 As EventHandler
   5:      Public Custom Event Event2 As EventHandler
   6:          AddHandler(ByVal value As EventHandler)
   7:              If Not ev2 Is Nothing Then
   8:                  ev2 = CType(System.Delegate.Combine(ev2, value), EventHandler)
   9:              Else
  10:                  ev2 = value
  11:              End If
  12:          End AddHandler
  14:          RemoveHandler(ByVal value As EventHandler)
  15:              If Not ev2 Is Nothing Then
  16:                  ev2 = CType(System.Delegate.Remove(ev2, value), EventHandler)
  17:              End If
  18:          End RemoveHandler
  20:          RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
  21:              ev2(sender, e)
  22:          End RaiseEvent
  23:      End Event
  25:      Protected Overridable Sub OnEvent2(ByVal e As EventArgs)
  26:          If Not ev2 Is Nothing Then
  27:              RaiseEvent Event2(Me, e)
  28:          End If
  29:      End Sub
  30:  End Class

In this example, Visual Basic allows you to implement exactly how Event2 is raised.  When I look at this in Reflector to see how C# uses this, here's what I see:

Reflector view of custom VB event

Reflector gives C# the raise keyword.  Why haven't the C# language experts done so?

How would this be worthwhile?  Well, suppose that we're building an application that can have plugins.  We don't know that plugins are always going to work correctly, so when they handle an event, they may raise an exception.  The problem is, if an event is invoked and the first event handler causes an exception, none of the successive handlers will be invoked.

Arguably, the "state of the application is undefined after an exception is raised, so we should gracefully exit."  But that's not always the case!  What if the way to gracefully do this is to analyze the stack trace within the application, determine which plugin caused the exception, and unload the plugin?  We can't do any of this from C#.

Give us the raise keyword!

This is the end of my "C# 4.0 Wishlist" series.  For reference, here are the other articles:

Posted on Sunday, January 27, 2008 11:25 PM | Back to top

Comments on this post: My C# 4.0 Wishlist, Part 5 : The raise Keyword

# re: My C# 4.0 Wishlist, Part 5 : The raise Keyword
Requesting Gravatar...
On a sidenote the way you raise the events there is a possible "raise" ;-) condition.
Left by Gabriel Lozano-Moran on Jan 28, 2008 5:57 AM

# Can be done in C#
Requesting Gravatar...

What you suggest can be done already in C# although certainly not in as elegant a way as a "raise" keyword:

foreach(Delegate del in MyEvent.GetInvocationList())
del(this, args);
catch(... ex)
// handle and unregister plugin here.

That's just off the top of my head but I have used similar before.
Left by Shaun Austin on Mar 04, 2008 5:56 AM

# re: My C# 4.0 Wishlist, Part 5 : The raise Keyword
Requesting Gravatar...
No, Shaun, I think you're missing the point: your code is great, but where do you intend to plug it? The RaiseEvent accessor in VB provides a hook for customizing the way the event is raised. In C#, you raise an event directly by referencing the underlying delegate, which is a little problematic because if the event is declared 'public,' so is the delegate. In VB, on the other hand, there is special syntax to raise an event, using the RaiseEvent keyword in a statement, which, in the case of a custom event, calls the RaiseEvent accessor. The best you can do in C# is provide an On<event name> method and hope that no one attempts to raise the event directly.
Left by Ron Inbar on Nov 04, 2008 5:50 AM

# re: My C# 4.0 Wishlist, Part 5 : The raise Keyword
Requesting Gravatar...
I hope I understand the discussion correctly :-)

In C#, the class containing the event controls how it is raised, even when it's public. See code below. Class A defines a public event, which class B tries to call. This gives you the following compiler error:

The event 'A.MyEvent' can only appear on the left hand side of += or -= (except when used from within the type 'A')

class A
public delegate void MyDelegate();
public event MyDelegate MyEvent;

class B
public void Test()
A a = new A();
a.MyEvent(); // error here

Actually, this is one of the differences between declaring a public delegate variable and a public event. For example, the following code compiles fine:

class A
public delegate void MyDelegate();
public MyDelegate MyEvent; // no event keyword

class B
public void Test()
A a = new A();
a.MyEvent(); // no error

Please note that in 'real' code, there should be a check for null-ness on the delegate or event before raising/calling it.

So, my point is: I think Shaun's solution is a good one.
Left by Martijn B on Apr 08, 2009 9:53 AM

Your comment:
 (will show your gravatar)

Copyright © Robert Paveza | Powered by: