RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Building Truly Useful Extension Methods

Use extension methods to breathe new life into old classes—even classes that you didn't write!

isual Studio 2008's new extension methods feature stands out from among Visual Studio's new offerings because you've been clamoring after it for years, right? What's that? You weren't clamoring for extension methods? Me neither.

Actually, Microsoft implemented extension methods to make it easier (perhaps even possible) to provide LINQ. And as long as they had to build extension methods anyway, they decided to give developers the option to use them—and then gave themselves credit for an amazing new tool!

Extension methods let you add new features to existing classes, even classes that you didn't write yourself. You can use them to add new methods to your own classes, classes written by other developers, and even sealed/final classes built by Microsoft such as Integer, Graphics, and String. You can even add extension methods to types built from simpler types, for example, integer or byte arrays.

This article explains how to create and use extension methods. It also shows how to add several useful methods to the String class (and one corresponding method to byte arrays). But first, the following section provides a word of warning.

Extension Methods and Encapsulation
Microsoft invented extension methods as a sneaky way to provide LINQ features. Microsoft's developers used them to add new methods to existing classes without needing to rebuild those classes. LINQ hides all the details so you don't really need to worry about what those extension methods are or where they are defined.

If you work at the LINQ level, everything's fine, but when you pry back the little plastic door that says "Warranty void if removed" and poke a screwdriver inside, things can get a bit confusing.

That's because extension methods have great potential to violate a class's encapsulation. Ideally, a class should embody a single, well-defined concept and wrap up all the data and methods associated with that idea in a nice neat little package. Using those hallowed precepts, you've constructed the ultimate Customer class.

Now, however, Belligerent Bob (an old FORTRAN programmer who thinks a class is something you take at school) can graft all sorts of extra baggage onto your elegant design. He can add methods that don't make sense for the class (he adds a ReorderInventory method to your Customer class). He can overload methods that you already created and give the new versions completely different and undocumented meanings (your version of the Sell method takes an Order as a parameter and invoices the Customer; his new version of Sell takes a URL as a parameter and spams the customer with whatever file is at that location). He can generally clutter the class's namespace with junk so it's hard to find what you want. Worst of all, he can put all this sordid code just about anywhere so it can be hard to find. (Then he'll check it out of Source Safe and keep it checked out forever so you can't fix any bugs in it!)

And if you were thinking that you might be able to thwart Bob's nefarious scheme by marking your Customer class NotInheritable, forget it. You can use extension methods to add new features to NotInheritable classes, which is a clear violation of intent.

Now, in real life this gloom-and-doom scenario probably won't play out in all its glory. After all, there are some interesting parallels between the Partial keyword (which I think Microsoft added largely so they could hide all the designer-generated code that used to clutter up form files) and extension methods. The Partial keyword promises the same potential for confusion—and that doesn't seem to have happened. Most people stick to good old tried-and-true methods for confusing themselves and don't bother using Partial.

But I'd like to offer some preemptive advice to hopefully prevent Belligerent Bob from doing too much damage.

First, before you add an extension method to a class, ask yourself whether it will be generally useful in many places within the project. If this is a one-shot deal, just write a subroutine near the code that uses it and let it go at that. In other words, if your program needs to check whether a file begins with a salutation ("Dear Mr. Phipps"), don't add a new method to the String class or the Stream class to do it.

Second, don't add extension methods to a class if the method doesn't really have much to do with that class. The Stream class is for reading and writing streams, not for examining their contents.

Third, don't overload an existing method with a new version that does something different. For example, the String class has a Trim method that removes specified characters form the ends of a string. Don't use extension methods to make a Trim method that takes different parameters (perhaps a string containing the target characters) and removes characters from the middle of the string. That would be confusing. Besides, you can already use the Replace method to do that.

Finally, document your extension methods so other programmers have at least a slim chance of figuring out what they do, and how to use them. Put them in modules with meaningful names such as CustomerExtensions, so they are easy to find.

I'm not saying that extension methods are evil, just that you should show some restraint when using them. Don't gratuitously use extension methods to add new features to a class just because you can.

Enough moralizing; it's time to explore extension methods in depth.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date