C# Extension Methods
Introduction
Extension methods have been part of the C# programming language since .NET 3.5 / Visual Studio 2008. An extension method is really nothing more than just a static method of a static class that can be called in a special way. In addition to being able to call an extension method directly by specifying the class and method name, an extension method can also be called on any type that is "extended by" the extension method.
// Traditional way to call static method MyClass.MyMethod()
var objectA = new object();
var a = MyClass.MyMethod( objectA );
// Calling MyClass.MyMethod() as an extension method
var objectB = new object();
var b = objectB.MyMethod();
Defining an Extension Method
In order to be called as an extension method, a method must be written to be an extension method. All of the following must be true:
- The method must be static
- The class that contains the method must be static
- The class that contains the method must not be a generic class
- The method must contain at least one argument (parameter)
- The first method argument must use the
this
keyword
public static class MyClass // Static Class
{
public static string MyMethod( // Static Method
this object obj) // First argument uses "this" keyword
{
...
return string;
}
}
An extension method is written to "extend" a specific type, and the type that it extends is always specified as the first argument of the method. The this
keyword, which can be used on the first argument of the method definition, tells the compiler that the method can be called as an extension method for the type specified using the this
keyword.
Any .NET type can be "extended" via an extension method. It does not matter if the type is a reference type or value type. For example, all of the following can be extended with extension methods:
- class
- interface
- struct
- delegate
- event
- enum
- built in types (bool, int, long, string, etc.)
- literals of any type
I have been asked in the past if there is such a thing as extension properties. Although that seems to be a much desired feature in the blogosphere, I am not aware of it currently being supported by any version of the C# compiler or planned for any future version, so you'll have to settle for methods that start with Get
or Set
if you need them.
Number of Arguments
By definition, an extension method must have at least one argument -- the this
argument -- to be an extension method. But, in addition to that one, it can have any number of other arguments including those that
- use the
ref
keyword - use the
out
keyword - have default values
- use the
params
keyword to indicate a variable number of arguments of the same type
Scope of Extension Method
As one would expect, an extension method can be called on the type that was explicitly specified using the this
keyword in the extension method definition. Additionally, any type that can be determined at compile time to be derived from, boxed to or implementing that type can also call the extension method.
In the previous section, MyClass.MyMethod()
is an extension method for the type object
. In .NET, of course, all types are derived from (or can be boxed to) an object
. In that specific example, because the extension method extends object
, that extension method can be called on literally any type that can exist within .NET. For example, all of the following would all be valid if MyMethod()
extended object
.
var c = 1.MyMethod();
var d = "Hello World".MyMethod();
public enum MyEnum
{
Red,
Green,
Blue;
}
var e = MyEnum.Red.MyMethod();
var f = anyFieldVariableOrProperty.MyMethod();
Although extension methods can be defined for type object
, that is not generally useful and should probably be avoid except for rare cases. It is much more practical to use an extension method with a narrower scope. For example, it is probably most common to define extension methods on a ...
- class -- Any object instantiated from that class or instantiated from any class derived from that class can be used to call the extension method
- interface -- Any object instantiated from a class that implements the interface
- sealed class -- Even if the class is sealed, you can still add extension methods to it since you are not really doing anything exception passing that object into a static method.
Null for the "this" argument
Since extension methods are static, the argument used for the "this" can actually be null, and the extension method will still get called without throwing an exception. For example, imaging calling the string function Trim()
in the following scenario.
string x = null;
string y = x.Trim(); // Boom! Throws a NullReferenceException because x is null
But, say there was an XTrim()
extension method defined as follows:
public static class StringExtensions
{
public static string XTrim(
this string value)
{
// If value is null or empty, then return value. Else, return the trimmed value.
return (string.IsNullOrEmpty(value))
? value
: value.Trim();
}
}
In that case, the following is perfectly valid and would not thrown an exception, and y
would end up with the value null
.
string x = null;
string y = x.XTrim(); // This sets y to null instead of throwing a NullReferenceException
The reason this last example does not throw a NullReferenceException
makes perfect sense: The value of x
, which happens to be null
, is passed in StringExtensions.XTrim()
as the value
argument. But, that method checks value
and only calls value.Trim()
if it is not null, so there is no NullReferenceException
.
Generally speaking, extension methods should gracefully handle a null value for the this
argument without throwing an exception
Sometimes it does not make sense to simply return a null
or some other default value if the this
argument is null. In such cases, rather than letting NullReferenceException
bubble out or throwing an ArgumentNullException
, it would be better to use a Try pattern that returns a true
/false
as the method return value, and returns the value of interest as an out
parameter.
public class MoreStringExtensions
{
public static bool TryDoSomething(
this string value,
out object obj)
{
if (string.IsNullOrEmpry(value))
{
obj = null;
return false;
}
.... do something to set obj ....
return (null != obj);
}
}
Using Generics with Extension Methods
When C# introduced generics back in 2.0, that really changed the game. Generics have become ubiquitous throughout .NET. Would you rather use an ArrayList
, or a List<string>
to hold an arbitrary number of strings?
C# extension methods fully support generic methods, but does not support generic classes. In other words, the following just won't work:
// This code will not even compile because you cannot define an extension method
// within a generic class
public static class MyGenericClass<T>
{
public static string MyExtensionMethod(
this string value)
{
}
}
But, you can create extension methods that use generics to template the this
argument, return false, something within the method, or any combination of the three. For example, all of the following are valid extension method prototypes.
public static class MyExtensionClass
{
// Uses T to template the "this" argument
public static void MyGenericExensionMethod1<T>(
this T value)
{
....
}
// Uses T to template the return type
public static T MyGenericExensionMethod2<T>(
this int value)
{
....
}
// Uses T to template something in the implementation
public static void MyGenericExensionMethod3<T>(
this int value)
{
....
}
// Uses T to template the "this" argument and return type
public static T MyGenericExensionMethod4<T>(
this T value)
{
....
}
}
The only trick is that you have to make sure to specify the type for T at the point of use.
TypeForY y = x.MyGenericExensionMethod2<TypeForY>();
Accessing Extension Methods and Distribution of Extension Methods
Since you do no specify the class name when calling an extension method, it is also not possible to specify a namespace for the extension method. That can lead to some interesting "compiler dilemmas".
For starters, to even known which extension methods are available, any static classes containing extension methods to be used within a file must exist within namespaces that are pulled in via a using directive
at the top of the file.
An extension method can be defined as a static method on any static, non-generic class. And, there are no requirements for all extension methods that extend the same type to be defined within the same class, assembly or namespace. Therefore, it is possible that there could be several different classes that define the exact same method prototype, thus creating two different extension method implementations of the same name and signature, and the compiler would not know which one to choose. In such cases, the compiler should create an ambiguous message of some kind and fail to compile.
It is also possible that an extension method could have the exact same signature (except for the this
argument) as method that already exists on the class that is extended by the extension method. For example, the extension method name could be unique now, but at some point in the future the class extended by the extension method could implement a method of the same name. In such cases, the method defined directly on the class is always chosen by the compiler instead of the extension method.
Programmer, Engineer