
Understanding Extension Methods
As you know, once a type is defined and compiled into a .NET assembly, its definition is, more or less, final.
The only way to add new members, update members, or remove members is to recode and recompile the code
base into an updated assembly. Or you could take more drastic measures such as using the System.
Reflection.Emit namespace to reshape a compiled type dynamically.
Extension methods allow you to extend the functionality of previously compiled types. Using extension
methods, you can add functionality to precompiled types while providing the illusion these methods were
that all along.
When you create extension methods, the existing precompiled assembly is not literally modified. Rather, the
type is extended within the current project. If you package extension methods into a custom .NET *.dll, other
applications would need to reference this library to make use of the extensions. To this end, extension
methods are really just a way to ‘pretend’ a type has new functionality. The real type is not modified in any
way.
This technique can be quite helpful when you need to inject new functionality into types for which you do
not have an existing code base. It can also be quite helpful when you need to force a type to support a set of
members (for the interest of polymorphism) but cannot modify the original type declaration. Also, LINQ
technologies make use of extension methods to integrate query expression support into the .NET base class
libraries.
In C#, extension methods can only be defined within a static class. All extension methods are marked as such
by using the this keyword as a modifier on the first (and only the first) parameter of the method in question.
This parameter represents the data type being extended. Once implemented, extension methods can be called
either from the correct instance in memory or statically via the defining static class.
In VB, extension methods must be marked with the <Extension> attribute. This attribute is defined within the
System.Runtime.CompilerServices namespace. Also, VB extension methods can only be defined in
Module types, not Class or Structure types.
Assume you are authoring a utility class named MyExtensions that defines a single extension method. The
method extends System.Object with a brand new method named DisplayDefiningAssembly(). Given that
Object is the parent to all .NET types, all types now have this new method.
// C#
using System.Reflection;
static class MyExtensions
{
// This method allows any object to display the assembly
// in which it is defined.
public static void DisplayDefiningAssembly(this object obj)
{
Console.WriteLine("{0} lives here: {1}", obj.GetType().Name,
Assembly.GetAssembly(obj.GetType()));
}
}
' VB
Imports System.Runtime.CompilerServices
Imports System.Reflection
Public Module MyExtensions
' This method allows any object to display the assembly
' in which it is defined.
<Extension()> _
Sub DisplayDefiningAssembly(ByVal obj As Object)
Console.WriteLine("{0} lives here: {1}", obj.GetType().Name, _
Assembly.GetAssembly(obj.GetType()))
End Sub
End Module
The first parameter of an extension method always denotes the type being extended. Of course, a given
extension method could have multiple parameters. To illustrate, here is an overloaded extension method for
the System.Int32 structure:
// C#
static class MyExtensions
{
...
// Every Int32 now has a Foo() method ...
public static void Foo(this int i)
{ Console.WriteLine("{0} called the Foo() method.", i); }
// ...which has been overloaded to take a string!
public static void Foo(this int i, string msg)
{ Console.WriteLine("{0} called Foo() and told me: {1}", i, msg); }
}
' VB
Module MyExtensions
...
' Every Int32 now has a Foo() method ...
<Extension()> Public Sub Foo(ByVal i As Integer)
Console.WriteLine("{0} called the Foo() method.", i)
End Sub
' ...which has been overloaded to take a string!
<Extension()> Public Sub Foo(ByVal i As Integer, _
ByVal msg As String)
Console.WriteLine("{0} called Foo() and told me: {1}", i, msg)
End Sub
End Module
Now consider the following usage. The VB code differs primarily by the declaration of the variables (via the
Dim keyword) and removal of semicolons.
// C#
static void Main(string[] args)
{
Console.WriteLine("***** Fun with Extension Methods *****\n");
// The int has assumed a new identity!
int myInt = 12345678;
myInt.DisplayDefiningAssembly();
// So has the DataSet!
System.Data.DataSet ds = new System.Data.DataSet();
ds.DisplayDefiningAssembly();
// And the SoundPlayer!
System.Media.SoundPlayer sp = new System.Media.SoundPlayer();
sp.DisplayDefiningAssembly();
// Use new integer functionality.
myInt.Foo();
myInt.Foo("Ints that Foo? Who would have thought it!");
// This would be an error! Booleans don’t have the Foo() method!
// bool b2 = true;
// b2.Foo();
}
Be aware that Visual Studio’s IntelliSense will show you which members are extension methods. Look for the
icon with a blue downward arrow. Notice in the following screen shot, DisplayDefiningAssembly() and
Foo() have the new extension method icon.
Understanding Extension Methods
Table of Contents
Copyright (c) 2008. Intertech, Inc. All Rights Reserved. This information is to be used exclusively as an
online learning aid. Any attempts to copy, reproduce, or use for training is strictly prohibited.
Courseware
Training Resources
Tutorials
Services