Sunday, November 9, 2008

An Interesting Delegate Usage

An interesting thing happened while I was surfing the MSDN C# forums. I was completely thrown for a loop when I came across some code posted by a regular contributor. It went something like this...

private void ACallBackFunction()
{
if(this.InvokeRequired)
this.Invoke(new ThreadStart(ACallBackFunction));
else
this.label1.Text = "Something or other";
}

The programming pattern should be very familiar to those using threads, because this is how a child thread updates the GUI (only the thread on which the GUI is created can update the UI). But, what seemed very strange was the use of "new ThreadStart(...)". I thought, what does a ThreadStart() delegate have to do with this operation?

The answer is ... nothing. But the application is none the less interesting. Here, the programmer decided to draw from a handy delegate in the C# tool chest just to get that required delegate to call "Invoke()" with. "ThreadStart" is a delegate type for a void method taking no arguments. It saved having to write a delegate type for the operation that might have looked like this...

delegate void ACallBackFunctionDelegate();

...just so that the program could later write...

private void ACallBackFunction()
{
if(this.InvokeRequired)
this.Invoke(new ACallBackFunctionDelegate(ACallBackFunction));
else
this.label1.Text = "Something or other";
}

So the by borrowing the pre-existing delegate declaration, namely ThreadStart, a few lines of coding were avoided. Now, I don't particularly like the implementation (it might lead a newbie astray). But, I do appreciate the awakening it caused in my thinking about delegates. Sometimes I would get all hung up in the declaration of the delegate and forget that the delegate need not be so tightly coupled to the method I'm intending it for. The delegate describes a well-typed variable for safely calling any number of methods which adhere to the prescribed signature.

Okay, so now I am more open minded about the re-use of my delegates as well. In fact, with the .NET Framework 3.x, there are a few new delegates that address the common signatures of many of our functions. The delegate types are "Action" and "Func". Both, are available as generic types making it very easy to construct a delegate variable on the fly similar to the example above. For example, one can write...

private void ACallBackFunction()
{
if(this.InvokeRequired)
this.Invoke(new Action(ACallBackFunction));
else
this.label1.Text = "Something or other";
}

The benefit of using "Action" instead of "ThreadStart", in my opinion, is it's a little less confusing.

No comments: