Extension Methods - Part 3 - Best practices

In the previous posts we had a look at what extension methods are, and how they work, and now we will consider how and when to use them.

Having bought a new hammer, everything seems to look like nails, but are there any concerns that you should have when using extension methods, and what would be best practice for use?

It is tempting to take all your utility and helper wrappers and convert them to extension methods, as it increases discoverability of the method to the developer, and makes the syntax more consistent than calling a static method on a wrapper. Compare these two:

IntUtility.IsEven(even);

even.IsEven();

But I would be worried about type pollution if extensions to the for instance the string method is a free for all, in that you might end up with an extension method hell, from all the various methods your developers have glued onto the type.

The following are the concepts that I so far consider to be helpful when implementing extension methods, and there are probably more.

Use when OO concepts don't apply

Extension methods should primarily be used when normal OO concepts don't apply, like when you're dealing with sealed classes, otherwise do as you would normally would do, and forget about extension methods.

Use to create syntactic sugar and increased readability

You can create a nice facade to existing functionality giving it a fluent interface and a Ruby like feel by doing something like this:

public static class Extensions 
{ 
	public static TimeSpan minutes(this int minutes)
	{
		return new TimeSpan(0, minutes, 0); 
	} 
	public static DateTime ago(this TimeSpan timeSpan) 
	{
		return DateTime.Now.Add(timeSpan.Negate()); 
	}
}
DateTime dt = 20.minutes().Ago();

See http://blog.troyd.net/

Methods should be cohesive with the type and serve a general purpose

The method should be cohesive with the type, and adequately generic, and use inheritance where this is not the case. Consider adding a method to validate phone numbers to int. This would not make sense, as not all instances of an int would need this method. The IsEven() method on the other hand is rather cohesive. Non-cohesive cases should lead to inheritance, where you specialize your type, to a PhoneNumber type in this case, having the appropriate instance methods.

Let developers opt-in to the extensions

Let developers opt-in to the extensions by putting them in their own discoverable namespace, like "Extensions.int" in this case, optionally specializing the namespace definitions further. I would consider it bad practice to define extension methods in namespaces that you have to import like System or core third-party namespaces. The latter could force you to get extension methods that your vendor think you want, if you decide to use their product - which would be very uncool.

Don't change state of the target

I would consider changing state of the object that the extension method applies to bad practice. The extension method should consider the object immutable, and you should instead return a new object, to keep your method side effect free.

Beware of silent rebinding

Consider the case, where you add an extension method to a type from the framework or a third-party class library, and the vendor decides to add a static instance method with the same name, but with different behavior. You would not get any compiler warnings, but the instance method would shadow the extension method, and change the behavior of your application. I'm not saying this will happen often, but it might.

Extension methods are a clever way of increasing discoverability and readability of code, and a handy way of allowing you to extend classes that you otherwise couldn't.

And if used with common sense, they will most definitely be an asset in the developers toolbox. But always keep an eye out for rebinding and issues with compile time resolving of methods.

Posted April 25, 2008 by Joachim Lykke Andersen
In

Comments [0]   
All comments require the approval of the site owner before being displayed.
OpenID
Please login with either your OpenID above, or your details below.
Name
E-mail
(will show your gravatar icon)
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):

Live Comment Preview