Saturday, March 25, 2006 - 13:34

Delegates & Events

So at my interview the day after my last post, the first question was: implement the IDispose pattern :-) So that worked out pretty well, although I did forget that the Finalize method uses the C++ Destructor syntax, and isn't a method named Finalize - which was pretty dumb.

The next question, though, was on delegates and events, and this is one that I always forget the syntax for - I tend to look it up in the MSDN when I need to use it, and then forget about it until next time. So to cement it in my head, and because it's actually quite tricky to find in the MSDN since there's so much stuff on Delegates and Events, here's a quick summary.

Delegates On Their Own

Basically, a delegate is a reference to a method. They can be used on their own, or more often, in conjunction with events. Delegates are really simple to declare:

// put this somewhere in your namespace
public delegate void MyDelegate(Object myParam);


Now if you're going to use this delegate to get one class to call methods belonging to another class (i.e. not using events), you'll need a method in that class that takes a delegate as a parameter:

// in your calling class
public void DoProcessing(MyDelegate processMethod)
{
Object obj;
// do something to populate the object
processMethod(obj);
}


The processMethod method will then be called in the context of this calling class. It will be declared in your second class:

// in your second class
public void someMethod(object obj)
{
// process the object
}


Then to actually use the delegate:

Caller.DoProcessing(new MyDelegate(c2.someMethod));


Alternatively, you can call the delegate directly:

object obj = "Hello";
MyDelegate md = new MyDelegate(obj);


So that's pretty simple. Using delegates with events is also pretty simple, provided you know how to use events:

Delegates & Events

You can declare your delegate as above, although if you're using it with events you'll probably want it to take an EventArgs parameter (or your own custom EventArgs class, which should then derive from the EventArgs base class). so let's use the MSDN example, of a list class which fires off a Changed event when an item in the list changes:


public delegate void ChangedEventHandler(object sender, EventArgs e);


Now within your class, declare an event of ChangedEventHandler type:

public event ChangedEventHandler Changed;


Now define a method that will fire off the event when an item changes:

protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}

And that's all there is to it, really - you'd call this OnChanged method in, say, the Add() or Delete() methods in your list, creating the EventArgs object and populating it as you require.

The only other thing you have to do is hook up the actual method that you want to handle the Changed event, which you'd do when you instantiate your list class:

private void ListChanged(object sender, EventArgs e)
{
Console.WriteLine("This is called when the event fires.");
}

// within your main method, or wherever you need this:
List list = new List();
List.Changed += new ChangedEventHandler(ListChanged);


There are some subtleties when inheriting classes with events - events themselves are not inherited, so you need to create a protected invoking method that derived classes can call, something like we did above. Better yet is to declare it as virtual, then the derived class can decide for itself whether to invoke the base event or provide one of its own.

Interestingly, events can be declared in interfaces.

If you are using a delegate which takes only an object 'sender' reference and an EventArgs class, you don't need to declare your own delegate, you can use the default .NET EventHandler delegate, which might save you a line or two of code :-)

So now that you can see how simple it is, go forth and delegate! (well, actually, don't - delegates can make your code very difficult to read and maintain. They have their place, and are sometimes essential, but use them because you need them, not just because you can!).

Update: I came across something odd today this with events. Actually, it's something I should have remembered, because I've come across it before - but I didn't. The point to remember is this: if a class subscribes to an event, and is eventually disposed, it will continue responding to the event until it's actually garbage collected. Counter-intuitive, I know, but that's how it works - so remember to unsubscribe from all events in your dispose method, otherwise you'll end up getting some odd behaviour!

Labels:

0 Comments:

Post a Comment

<< Home