Saturday, February 21, 2009

Respect your extension methods

One of the nice things in C# 3.0 is extension methods. I won't go into details about it but would like to focus on the hazards when actually writing beyond the plain examples.
However, I will use a plain example myself since I don't want you to fall asleep.

Since the method binding is done at compile time, you will get a different behavior depending on the assigned type.

Suppose we have 2 (plain) objects:


public class BaseObject
{ }
public class DerivedObject : BaseObject
{ }

Now for the extension method:


public static class ObjectExtensions
{
public static void ExtensionMethod(this BaseObject obj)
{
Console.WriteLine("In BaseObject extension version");
}
}

The Main method is very simple:


static void Main(string[] args)
{
BaseObject baseObj = new BaseObject();
DerivedObject derObj = new DerivedObject();
baseObj.ExtensionMethod();
derObj.ExtensionMethod();
}

I've declared 2 objects and when I run this sample I get:
In BaseObject extension version
In BaseObject extension version

So far so good; 2 object, 1 extension and 1 expected result for both calls.
Remember the compile time binding thing? Lets add the another version for the extension method. It goes like:


public static void ExtensionMethod(this DerivedObject obj)
{
Console.WriteLine("In DerivedObject extension version");
}

Now, when running this sample again, I get:
In BaseObject extension version
In DerivedObject extension version

"Is he ever going to get to the point?"
Well, the point is this: add these 3 lines to the main method and see what happens.
BaseObject[] arrOfObj = { baseObj, derObj };
arrOfObj[0].ExtensionMethod();
arrOfObj[1].ExtensionMethod();

We are back to BaseExtension for both new calls even though one of them is a derived type.

The danger is obvious. It is very easy to keep your gourds down and write some buggy lines of code that will make you bold trying to figure out what the heck went wrong.
Of course, there are other words of caution in this subject:

When it comes to your extension method versus the original object version, yours will always loose. The extended version will never be called.
"Why the heck would you extend a method that already exists?"
Well, the first option is that it didn't exist at the time and was added to the object at a later point of .net life. You know, great minds think alike.
The second option is that I tried to override the original behavior. No treats for me in both poor scenarios!

"Well, am I at list entitled to access some private fields of the extended object?"
Hmm, no! You see, extension method is just a way to call a static method from the instantiated object.

You will find many great examples on how to do nifty things with extensions.
My advice is to avoid it if you can inherit and add it in the derived object. In case you can't or don't have access to the code then use it with care.

No comments:

Post a Comment