Introduction
This article will try to explain what extension methods are and how you can use them for your own application.
Background
Every static
helper class can be converted to extension methods, so only basic knowledge of classes in .NET is required.
Using the Code
This article uses Visual Studio 2008. Although Visual Studio 2005 also allows you to use the .NET 3.5 features, its intellisense support isn't that great. For most of the code it shouldn't be a problem to use it in Visual Studio 2005.
The Problem
If you ever wanted to add extra functionality to an existing class, if you were lucky and the class wasn't sealed, you could override it and add the extra method. This wasn't always what you wanted, and sometimes it's not possible at all.
Take an interface for example, IEnumerable<T>
, what do we know about it?
The MSDN description is:
Exposes the enumerator, which supports a simple iteration over a collection of a specified type.
So every collection should implement this interface, it doesn't matter if it's a list or an array, we only know that we can get the elements back.
The Solution
We have declared an array of string
s to work with.
string[] strings = new string[] { "Green", "Yellow", "Red", "Blue" };
So let's say we want the last element of this IEnumerable<T>
.
Writing code to solve these problems in .NET 2.0 would require static
helper methods, we could solve it with this simple helper method:
public static class EnumerableHelpers
{
public static T Last<T>(IEnumerable<T> enumerable)
{
if (enumerable == null)
{
throw new ArgumentNullException("enumerable");
}
T last = default(T);
foreach (T item in enumerable)
{
last = item;
}
return last;
}
}
We could also add some typechecking on IList
but this sample will always work. If the IEnumerable
was empty, it would return the default value for T, null
for classes and 0
for int
etc.
The code is also easy to use and can be used on any enumerable.
string last = EnumerableHelpers.Last(strings);
The compiler knows which generic type to use so we don't have to write Last<string>
. But it doesn't look as good as being able to type strings.Last()
.
Now the only thing we need to change is add the special keyword for an extension method which is this
before the first parameter. And it always has to be the first parameter.
public static class EnumerableHelpers
{
public static T Last<T>(this IEnumerable<T> enumerable)
{
if (enumerable == null)
{
throw new ArgumentNullException("enumerable");
}
T last = default(T);
foreach (T item in enumerable)
{
last = item;
}
return last;
}
}
With this change, the compiler knows it can use this method on any IEnumerable<T>
and will even show intellisense for it.
Our last code sample can now be defined as:
string last = strings.Last();
which makes it seem like it is just a method of IEnumerable<string>
.
Usage In .NET 3.5
All these extension methods for any Enumerable are already implemented with .NET 3.5 and are the basics for LINQ.
It doesn't matter if it's a List
or an Array
or any other collection. It just matters that it supports the IEnumerable<T>
interface.
The only extra that you get is another new syntax to call them like this one:
IEnumerable<int> result =
from s in strings where s.Length > 4 select s.Length;
which can be translated to using extension methods:
IEnumerable<int> result2 =
strings.Where(s => s.Length > 4).Select(s => s.Length);
Another new feature that shows up here are lambda expressions, they won't be explained here maybe some other time.
You could easily rewrite them to be more .NET 2.0 by using anonymous delegates:
IEnumerable<int> result3 =
strings.Where(delegate(string s)
{ return s.Length > 4; }).Select(delegate(string s)
{ return s.Length; });
Almost there now, we could also get rid of the extension methods completely.
IEnumerable<int> result4 =
Enumerable.Select(Enumerable.Where(strings, delegate(string s)
{ return s.Length > 4; }), delegate(string s) { return s.Length; });
If you see what is translated for this small LINQ query (just a simple where
and select
), you can imagine what it'll do when you start creating more complex queries.
Conclusion
Extension methods are very easy to use and when used properly will make your code much more readable. They can be used on anything (Classes, Interfaces, Structs, Enums, ...) which makes them a powerful tool.
The included source code has the code snippets that are used in this article and some other extension methods that you can use.
History
- October 25, 2007: First version