Now that visual studio.net 2008 has been released developers have a much improved development environment and framework to produce high quality code with. Extension methods are one of the new framework and IDE features that provides a powerful and clever method of extending objects that you do not have source code for or otherwise can't directly extend.
Simply put, extension methods allow you to add new methods to the public contract of an existing type without sub-classing, decorating or recompiling the original type. Prior to this release there were a few options available to solve this problem.
The Decorator Pattern
The decorator is a great design pattern for extending the functionality of an object without sub-classing. Without going into the nitty gritty details of decorator implementation, essentially you create an object that takes the object that you want to decorate as an argument to your new objects constructor. Next, you'd create whatever methods you need in your object, accessing the "decorated" object as needed.
Using this pattern, you can extended the functionality of an existing object without subclasing or resorting to libraries of static methods. Unfortunately this pattern is overkill for minor object extensions or use with value types. I commonly use this pattern to create read-only versions of objects without having to change the functionality of the underlying object. Another great example are the various stream objects in the System.IO namespace.
Subclassing
This option is self explainatory. Simply create an object that inherits from the object you want to extend and add additional functionality. Unfortunately if your object to extend is sealed you'll need to use a decorator or the dreaded "helper".
The "Helper" Object
Nearly every piece of software that I've ever supported has one or fifty of these objects. I've seen string helpers, integer helpers, business object helpers, User Interface helpers, and ADO.NET helpers to name just a few.
Personally I don't care for this technique, though it can be extremely effective for minor object extension or use with value types. It is susceptible to abuse through massive overloading, lack of commenting and documentation and poor overall design.
Enter the Extension Method
Essentially, these methods are similar to the static methods used in the helper object with one very important distinction; they exist as methods defined as part of the contract of the defined type.
public static class Extensions {
public static bool InRange(this T value, T lower, T upper) where T : struct, IComparable {
if(value.CompareTo(lower) >= 0 && value.CompareTo(upper) <= 0) {
return true;
}
return false;
}
}
In this example I've illustrated a very powerful generic method that allows a developer to see if a value falls into a range of acceptable values. Because it is generic and constrained by the IComparable
decimal price = 12.99;
if(price.InRange(1, 49.95)){
Console.WriteLine("The price specified is within the specified range.");
}else{
Console.WriteLine("The price specified is not within the specified range.");
}
This particular extension method is configured using the decimal type, though it will work for any struct that implements the IClomparable interface. What's important is that visual studio.net 2008 will display this method using intellisense on objects that match both the this (generic) declaration as well as the interface constraint.There are countless applications for extension methods. They provide a more intuitive method of extending objects without resorting to other techniques that might require extensive design consideration.