Sunday, November 16, 2008

.NET 2.0 Extension Methods

I regularly write programs in C# on Visual Studio 2008. The default Framework for the environment is 3.5. But sometimes I must re-target 2008 to Framework 2.0. Is it possible to take advantage of the new "Extension Method" language feature of 2008 when required to target 2.0? This is a good question and applies to more than the extension methods. But for now, let's answer the question for extensions.

Yes.

But, you need to do some of the work yourself. The compiler's support for extension methods is really unconnected with Framework 3.5. But maybe you've seen the error...


Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll?


To write an extension, you need the ExtensionAttribute somewhere, anywhere. The compiler is looking for it in the System.Runtime.CompilerServices namespace which is in System.Core.dll. The 2.0 and 3.5 versions of this DLL are different. The good news is you don't need the whole 3.5 DLL, you just need the ExtensionAttribute class and you can actually write it yourself.

So, here I have written the class you need in C#.

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(
        AttributeTargets.Assembly
        |AttributeTargets.Class
        |AttributeTargets.Method,
        Inherited=false,
        AllowMultiple=false)
    ]
    public class ExtensionAttribute : Attribute
    {
    }
}

Add this to a new class file or an existing file. Make sure you add it outside of all other namespace definitions since you will be adding to the System.Runtime.CompileServices namespace.

That's all it should take. Good luck with your projects and using extension methods in C# with Framework 2.0.

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.