Thursday, 18 September 2014

Using Delegates and Events in C#

I wrote this mainly to remind myself what needs doing.
I don't often use delegates and it takes me too long to relearn it. What I wanted was a quick overview and reminders of how to do them. Here are my notes. I hope they help you too.


Delegates or Events?

Using Event doesn't support a return value but prevents subscribers to the event from affecting other subscribers (e.g. delegate=null) and from firing the event.


Events 

Pass parameters using a class derived from EventArgs
    public class FileNameEventArgs : EventArgs {
        public string FileName { get; set; }
        public FileNameEventArgs(string FileName) {
            this.FileName = FileName;
        }
    }
By using an event we don't need to declare the delegate, we can use EventHandler<T>
Declare the event in the source class
public event EventHandler<FileNameEventArgs> FileNameChanged;
Add a method for firing the delegate in the source class
    protected virtual void FileNameChange(string NewFileName) {
        EventHandler<FileNameEventArgs> handler = FileNameChanged;   //ensures our handler can't change between test for null and invoke.
        if (handler != null) {
            handler(this, new FileNameEventArgs(NewFileName));
        }
    }
In the client, write a handler for the event
    public void OnFileNameChange(object sender, FileNameEventArgs e) {
        Console.WriteLine(e.FileName);
    }
Subscribe to the event
    EventSourceClass.FileNameChanged += OnFileNameChange;

If there are no arguments to pass then we don't need FileNameEventArgs, we can simply use EventArgs, the default parameter type for EventHandler
public event EventHandler<FileNameEventArgs> FileNameChanged;
 becomes
public event EventHandler FileNameChanged;
and
EventHandler<FileNameEventArgs> handler = FileNameChanged;
if (handler != null) {
    handler(this, new FileNameEventArgs(NewFileName));
 becomes
EventHandler handler = FileNameChanged;
if (handler != null) {
    handler(this, new EventArgs());
and
public void OnFileNameChange(object sender, FileNameEventArgs e) {
 becomes
public void OnFileNameChange(object sender, EventArgs e) {

Delegates

We can use a delegate instead of an EventHandler by replacing the line:
public event EventHandler<FileNameEventArgs> FileNameChanged;
with a delegate...
Declare the delegate
public delegate void FileNameChangeDelegate(object sender, FileNameEventArgs e);
Instantiate a delegate
public event FileNameChangeDelegate FileNameChanged;
By using a delegate we lose the protection of EventHandler, but we are no longer restricted to the prototype void (object, EventArgs); e.g. we could have
public delegate int FileNameChangeDelegate(string NewFileName, bool LocalFile);