static void

Events and Delegates

A delegate is an object representing a function pointer. It is defined with a method signature (the return type and argument).

public delegate string MyDelegate(bool isOK);

An event tells subscribers that they must use a method that looks like the delegate.

public event MyDelegate MyEvent;

In .Net 2 you can avoid creating a delegate with the generic EventHandler (msdn)

public event EventHandler<MyEventArgs> MyEvent;

Declare Event

A generic EventArgs<T> : EventArgs is handy for passing strong typed data (strings, int, object)

public class Worker
{
    public event EventHandler<GenericEventArgs<string>> WorkDone;
    public void Execute(string m)
    {
      EventHandler<GenericEventArgs<string>> handler = WorkDone;
      if (handler != null) handler(this, new GenericEventArgs<string>(m));
    }
}

public class GenericEventArgs<T> : EventArgs
{
    public GenericEventArgs(T data)
    {
        Data = data;
    }
    public T Data { getset; }
}

Raise Event

To raise the event (publish it):

//cast the delegate as the event. If there is no subscriber, the event is null
MyDelegate handler = MyEvent;
if (handler != null) handler(this, args);

You must use the raise event pattern (see C# faq). NB: if you don't assign the copy, it's not thread safe (there's a race condition between the check and the useage).

if (MyEvent != null) MyEvent(this, EventArgs.Empty); //compiles but not thread safe!!

In C# 6.0 the ?. null conditional operator is thread-safe.

MyEvent?.Invoke(thisEventArgs.Empty);

Consume Event

To consume it from a subscriber:

WorkClass wc = new WorkClass(); //scope needs to be class level
wc.MyEvent += new WorkClass.MyDelegate(MySubscriberMethod); //the new EventHandler syntax is optional...
wc.MyEvent += MySubscriberMethod; //works too!

You can inline it and use local variables:

decimal totalWeight; // Local
wc.FoundWeight +=
    (delegate(object sender, GenericEventArgs<decimal> e) { totalWeight += e.Data; });
//or v3 lamdba style
shipper.RecordCTotalWeight += ((sender, e) => totalWeight += e.Data);