Do not make assumptions on the object’s state after raising an event.

Prepare for any changes to the current object’s state while executing an event handler. The event handler may have called other methods or properties that changed the object’s state (e.g. it may have disposed objects referenced through a field).

Always document from which thread an event handler is called.

Some classes create a dedicated thread or use the Thread Pool to perform some work, and then raise an event. The consequence of that is that an event handler is executed from another thread than the main thread. For such an event, the event handler must synchronize (ensure thread-safety) access to shared data (e.g. instance members).

Raise events through a protected virtual method.

If a derived class wants to intercept an event, it can override such a virtual method, do its own work, and then decide whether or not to call the base class version. Since the derived class may decide not to call the base class method, ensure that it does not do any work required for the base class to function properly.

Name this method OnEventName, where EventName should be replaced with the name of the event. Notice that an event handler uses the same naming scheme but has a different signature. The following snippet (most parts left out for brevity) illustrates the difference between the two.

///<summary>An example class</summary>
public class Connection
{
  // Event definition
  public event EventHandler Closed;

  // Method that causes the event to occur
  public void Close()
  {
    // Do something and then raise the event
    OnClosed(new EventArgs());
  }

  // Method that raises the Closed event.
  protected OnClosed(EventArgs args)
  {
	  Closed(this, args);
  }
}

///<summary>Main entrypoint.</summary>
public static void Main()
{
  Connection connection = new Connection();
  connection.Closed += new EventHandler(OnClosed);
}

///<summary>Event handler for the Closed event</summary>
private static void OnClosed(object sender, EventArgs args)
{
// Implementation left out for brevity.
}

Use the sender/arguments signature for event handlers.

The goal of this recommendation is to have a consistent signature for all event handlers. In general, the event handler’s signature should look like this

public delegate void MyEventHandler(object sender, EventArgs arguments)

Using the base class as the sender type allows derived classes to reuse the same event handler.

The same applies to the arguments parameter. It is recommended to derive from the .NET Framework’s EventArgs class and add your own event data. Using such a class prevents cluttering the event handler’s signature, allows extending the event data without breaking any existing users, and can accommodate multiple return values (instead of using reference fields). Moreover, all event data should be exposed through properties, because that allows for verification and preventing access to data that is not always valid in all occurrences of a certain event.

Implement add/remove accessors if the number of handlers for an event must be limited.

If you implement the ‘add’ and ‘remove’ accessors of an event, then the CLR will call those accessors when an event handler is added or removed. This allows limiting the number of allowed event handlers, or to check for certain preconditions.

Consider providing property-changed events.

Consider providing events that are raised when certain properties are changed. Such an event should be named PropertyChanged, where Property should be replaced with the name of the property with which this event is associated.

Consider an interface instead of a delegate.

If you provide a method as the target for a delegate, the compiler will only ensure that the method signature matches the delegate’s signature.

This means that if you have two classes providing a delegate with the same signature and the same name, and each class has a method as a target for that delegate, it is possible to provide the method of the first class as a target for the delegate in the other class, even though they might not be related at all. Therefore, it is sometimes better to use interfaces. The compiler will ensure that you cannot accidentally provide a class implementing a certain interface to a method that accepts another interface that happens to have to same name.