Extension methods were introduced in C# 3.0. Extension methods extend and add behavior to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. They are especially helpful when you cannot modify the source of a type you are looking to enhance. Extension methods may be created for system types, types defined by third parties, and types that you have defined yourself. The extension method can be invoked as though it were a member method of the original type. This allows for Method Chaining used to implement a Fluent Interface.
An extension method is created by adding a static method to a static class which is distinct from the original type being extended. The static class holding the extension method is often created for the sole purpose of holding extension methods.
Extension methods take a special first parameter that designates the original type being extended. This first parameter is decorated with the keyword this
(which constitutes a special and distinct use of this
in C#—it should be understood as different from the use of this
which allows referring to members of the current object instance).
In the following example, the original type being extended is the class string
. String
has been extended by a method Shorten()
, which provides the additional functionality of shortening. The static class StringExtensions
has been created to hold the extension method. The extension method Shorten()
shows that it is an extension of string
via the specially marked first parameter. To show that the Shorten()
method extends string
, the first parameter is marked with this
. Therefore, the full signature of the first parameter is this string text
, where string
is the original type being extended and text
is the chosen parameter name.
static class StringExtensions
{
public static string Shorten(this string text, int length)
{
return text.Substring(0, length);
}
}
class Program
{
static void Main()
{
// This calls method String.ToUpper()
var myString = "Hello World!".ToUpper();
// This calls the extension method StringExtensions.Shorten()
var newString = myString.Shorten(5);
// It is worth noting that the above call is purely syntactic sugar
// and the assignment below is functionally equivalent
var newString2 = StringExtensions.Shorten(myString, 5);
}
}
The object passed as the first argument of an extension method (which is accompanied by the this
keyword) is the instance the extension method is called upon.
For example, when this code is executed:
"some string".Shorten(5);
The values of the arguments are as below:
text: "some string"
length: 5
Note that extension methods are only usable if they are in the same namespace as their definition, if the namespace is imported explicitly by the code using the extension method, or if the extension class is namespace-less. The .NET framework guidelines recommend putting extension classes in their own namespace. However, this may lead to discovery issues.
This results in no conflicts between the extension methods and the libraries being used, unless namespaces which might conflict are explicitly pulled in. For example LINQ Extensions:
using System.Linq; // Allows use of extension methods from the System.Linq namespace
class Program
{
static void Main()
{
var ints = new int[] {1, 2, 3, 4};
// Call Where() extension method from the System.Linq namespace
var even = ints.Where(x => x % 2 == 0);
}
}
Since C# 6.0, it is also possible to put a using static
directive to the class containing the extension methods. For example, using static System.Linq.Enumerable;
. This makes extension methods from that particular class available without bringing other types from the same namespace into scope.
When a class method with the same signature is available, the compiler prioritizes it over the extension method call. For example:
class Test
{
public void Hello()
{
Console.WriteLine("From Test");
}
}
static class TestExtensions
{
public static void Hello(this Test test)
{
Console.WriteLine("From extension method");
}
}
class Program
{
static void Main()
{
Test t = new Test();
t.Hello(); // Prints "From Test"
}
}
Note that if there are two extension functions with the same signature, and one of them is in the same namespace, then that one will be prioritized. On the other hand, if both of them are accessed by using
, then a compile time error will ensue with the message:
The call is ambiguous between the following methods or properties
Note that the syntactic convenience of calling an extension method via originalTypeInstance.ExtensionMethod()
is an optional convenience. The method can also be called in the traditional manner, so that the special first parameter is used as a parameter to the method.
I.e., both of the following work:
//Calling as though method belongs to string--it seamlessly extends string
String s = "Hello World";
s.Shorten(5);
//Calling as a traditional static method with two parameters
StringExtensions.Shorten(s, 5);