Click here to Skip to main content
15,899,754 members
Articles / Programming Languages / C#
Article

How To Use Extension Methods

Rate me:
Please Sign up or sign in to vote.
3.64/5 (13 votes)
25 Oct 2007CPOL3 min read 43.6K   163   41   15
Explains how extension methods work and how you can use them.
Extension Method Intellisense

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 strings to work with.

C#
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:

C#
public static class EnumerableHelpers
    {
        public static T Last<T>(IEnumerable<T> enumerable)
        {
            if (enumerable == null)
            {
                throw new ArgumentNullException("enumerable");
            }
            // We know we can foreach through it
            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.

C#
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.

C#
public static class EnumerableHelpers
    {
        public static T Last<T>(this IEnumerable<T> enumerable)
        {
            if (enumerable == null)
            {
                throw new ArgumentNullException("enumerable");
            }
            // We know we can foreach though it
            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 custom extension method

Our last code sample can now be defined as:

C#
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:

C#
IEnumerable<int> result = 
    from s in strings where s.Length > 4 select s.Length;

which can be translated to using extension methods:

C#
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:

C#
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.

C#
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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
President 2sky
Belgium Belgium
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalnice on Pin
Pranay Rana30-Dec-10 0:05
professionalPranay Rana30-Dec-10 0:05 
Questionwhat are the risks when extending an established core class with additional methods Pin
Alexis Rzewski7-Jun-08 1:24
Alexis Rzewski7-Jun-08 1:24 
Just because YOU CAN doesn't mean it is necessarily a good thing to do. Extending a class's API with additional signatures means diverting the original designer's intent with your own custom design, additionally polluting the namespace. Case in point: the DateTime class. It is well known to all that it doesn't have much information of month names. That's because it is found in GregorianCalendar, when the culture info is United States and using the English language. So, getting today's month name is a bit cumbersome, having to use many separate classes just to get that info. Ever tried populating a dropdown listbox with english month names, January to December? not so obvious... So, the developer might be tempted on extending the DateTime class with MonthNameArray that returns string[] (an array of strings). Fine. That was in one departmental project. In another departmental project, they might be doing their own custom extensions to the DateTime class. Then, developers migrate from one project to another, and bring with them their own personal extensions, and add them again to the new project's DateTime class. OK, now, pressing the dot shows IntelliSense retrieving HUNDREDS of new methods, some may be named PrintMMDDYYYY, PrintLongMonthDayLongYear, etc etc. Just imagine when a manager wants to merge these two apps. You might just have two separate methods, similarly named, that might just do almost the same thing. Or, what about when you "reuse" some code, but this code is invoking methodds that don't exist in your DateTime class... Guess what: you will be forced to extend your DateTime class with their extensions. This is a new feature that is being allowed by the compiler. People think it is cool. Great. Now the gates are open. Before going gung-ho on these extensions, consult with other developers that have used them in other programming environments, and ask them about the pros and cons, specially after a couple of years on a project. You will see there is a price in future maintenability. My advice: add extensions to a class only when there is no other way to do what you want to do. If there is a different pattern or helper class that achieves the same goal, go for that solution. If you inherited a DLL-ized component for which you do not have the source code, and the API framework that you are using requires that this DLL-ized component, in order to be usable, needs to understand the message being sent to it named "DisplayValueName" and it takes a signature of "string, int", then, go ahead, and extend that DLL-ized component with public void DisplayValueName (string param1, string int). And yes, not allowing properties to be extended a well is an annoying disadvantage. Example: you have a listbox whose DisplayMember is a property named "DisplayValue". You might have two types of objects in that listbox, one from a class you have the source code for, and another that you don't, and it does not allow subclassing. Unfortunately, there is no way to extend the second class with the property "DisplayValue", and the listbox will not be displaying those objects correctly.
AnswerRe: what are the risks when extending an established core class with additional methods Pin
Steve Hansen8-Jun-08 22:08
Steve Hansen8-Jun-08 22:08 
GeneralI liked it Pin
Johan Fourie30-Oct-07 13:47
Johan Fourie30-Oct-07 13:47 
GeneralRe: I liked it Pin
Steve Hansen30-Oct-07 15:37
Steve Hansen30-Oct-07 15:37 
GeneralA bit confusing Pin
WillemM25-Oct-07 1:42
WillemM25-Oct-07 1:42 
GeneralRe: A bit confusing Pin
Steve Hansen25-Oct-07 2:25
Steve Hansen25-Oct-07 2:25 
GeneralRe: A bit confusing Pin
WillemM25-Oct-07 3:47
WillemM25-Oct-07 3:47 
GeneralRe: A bit confusing Pin
Ben Daniel25-Oct-07 15:35
Ben Daniel25-Oct-07 15:35 
GeneralRe: A bit confusing Pin
Steve Hansen25-Oct-07 20:19
Steve Hansen25-Oct-07 20:19 
GeneralRe: A bit confusing Pin
brian_agnes31-Oct-07 5:17
brian_agnes31-Oct-07 5:17 
GeneralRe: A bit confusing Pin
Steve Hansen31-Oct-07 5:25
Steve Hansen31-Oct-07 5:25 
GeneralRe: A bit confusing Pin
urbane.tiger4-Nov-07 14:48
urbane.tiger4-Nov-07 14:48 
GeneralI like your article Pin
HummerX9-Dec-07 17:28
HummerX9-Dec-07 17:28 
GeneralRe: I like your article Pin
Steve Hansen9-Dec-07 20:29
Steve Hansen9-Dec-07 20:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.