C# Extension Methods

Sometimes it is necessary to add functionality to a library for which you do not own the source code and where using inheritance to subclass functionality is not viable. This problem can be overcome with the careful use of C# 3.0 extension methods.
An extension method is a type of method that was introduced in C# version 3.0. Extension methods allow you to create new functionality for existing data types, including classes,structures or interfaces, without modifying the code of the type itself. This permits new methods to be created for classes for which you have no access to the source code, including the standard types in the .NET framework libraries or those in third-party assemblies.
In previous versions of the C# language, you could modify the functionality of classes only by inheriting from the existing types and adding functionality in a subclass. However, if the existing classes are sealed this is not possible. With extension methods, you can add functionality to sealed types.
You can create extension methods for base classes in inheritance hierarchies. Any method added to a base class is automatically implemented for all subclasses too. Similarly, an extension method for an interface is added to all types that implement the interface.
Microsoft use extension methods extensively for the language integrated query (LINQ) system. The standard LINQ operators, such as Select, Where and OrderBy, are extension methods that are added to the IEnumerable and genericIEnumerable(T) interfaces.
Extension Method Limitations
Extension methods do not modify the extended class. They are defined externally and these definitions cannot be used to override existing methods of the type. An extension method will never be called if it has the same signature as an existing class member.
It is important that the principle of encapsulation is not violated by extension methods. To prevent this, extension methods do not have access to any private members of the extended class. They may only work with externally visible members.
It is possible to create two or more extension methods with identical signatures. If two extension methods with matching signatures are visible for the same base class, the code will not compile. This problem can be circumvented by defining the extension methods in separate namespaces and ensuring only one of the namespaces is referenced in a using directive in any single code file.
Creating Extension Methods
Although an extension method is accessed as if it where an instance method of the extended type, it must actually be defined as a static member of a static class. To signify that the new member is an extension method, the first argument must be of the type being modified and must be preceded by the “this” keyword.
The first parameter is never used in calls to the method as it represents the object itself.
The declaration uses the following syntax:


public static result-type name(this obj-type obj, type1 param1, ..., typeX paramX)

The result-type specifies the type that will be returned by the extension method. This is identical to the return type of any other method declaration. The first parameter includes two elements; obj-type is the name of the type that will be extended by the method and obj will contain the object when a call is made. The remaining parameters are those that will be included in any call to the method. These are optional.
A Simple Extension Method
To demonstrate the use of extension methods, we can add a new method to the string data type. String is sealed and so cannot be subclassed, giving an interesting example. Our simple extension method will output the contents of the string to the console. To begin, create a new console application.
All extension methods must be declared within a static class. Ideally this would also be in a separate namespace. However, for simplicity in this article’s sample code, we will simply create a new static class within the namespace provided by the console application. Add the following class:


public static class SampleExtensionMethods
{
}

We can now create the new extension method inside the SampleExtensionMethods class. Note the use of the “this” keyword for the first parameter:


public static void OutputToConsole(this string s)
{
Console.WriteLine(s);
}

Now that the extension method has been created, it is visible as an instance member for all strings. We can test this by modifying the Main method of the program so that it creates a new string and calls the new method:


string testString = "Hello, world.";
testString.OutputToConsole(); // Outputs "Hello, world."

If you are using Visual Studio, you will see that the new method appears in the list of members that is displayed by the Intellisense feature. Note that the item has a different icon to the real instance methods, indicating its status as an extension method.
Adding Parameters
Extension methods may include parameters as with any other type of method. The parameters that will be used in the calls to the method must be added after the argument that is decorated with the “this” keyword.
To demonstrate, we can modify our method to accept two parameters. These will be outputted to the console as a prefix and a suffix.


public static void OutputToConsole(this string s, string prefix, string suffix)
{
Console.WriteLine("{0}{1}{2}", prefix, s, suffix);
}

To test the modified extension method, update the Main method of the program:


string testString = "Hello, world.";
testString.OutputToConsole("[", "]"); // Outputs "[Hello, world.]"

Extension Methods and Inheritance
When an extension method is applied to a base class, all of its subclasses are also affected. We can demonstrate this quickly with an unusual example that would generally not be used in a real-world system.
In this case, we will modify the existing extension method so that it is applied to the Object class, rather than the String class. As every class and structure is derived from System.Object, every class and structure will receive the new member.
Modify the extension method as follows:


public static void OutputToConsole(this object o)
{
Console.WriteLine(o);
}

At this time, the program will still compile and execute because the string that we are using is a subclass of System.Object. We can improve the example by adding more variables to the Main method:


string testString = "Hello, world.";
testString.OutputToConsole(); // Outputs "Hello, world."
int testInt = 99;
testInt.OutputToConsole(); // Outputs "99"
object testObject = new object();
testObject.OutputToConsole(); // Outputs "System.Object"

Extension Methods and Interfaces
One of the more interesting uses of extension methods is the extending of interfaces. When an extension method is created with the first parameter referring to an interface, all types that implement the interface receive the new method. This provides a manner for attaching real functionality to an interface, rather than providing a signature to be implemented by each class individually. The main limitation is that the extension method may only access members of the interface.
To demonstrate, add the interface shown below to the console application. This interface represents the individual products in a stock inventory system.


public interface IProduct
{
string StockCode { get; set; }
int QuantityInStock { get; set; }
double Price { get; set; }
}

Next, create a new class that implements the IProduct interface, as follows:


class Product : IProduct
{
public string StockCode { get; set; }
public int QuantityInStock { get; set; }
public double Price { get; set; }
}

Finally, we can add an extension method to the IProduct interface. Add this within the existing
SampleExtensionMethods class:


public static double StockValue(this IProduct product)
{
return product.Price * product.QuantityInStock;
}

As the Product class implements the IProduct interface, the new StockValue method is automatically available. Modify the Main method as follows to show the method’s operation:


Product p = new Product {StockCode = "RAM", QuantityInStock = 100, Price = 49.99};
double stockValue = p.StockValue();
stockValue.OutputToConsole(); // Outputs "4999"

Guidelines
Extension methods can be very useful. However, because the code for extension methods is held separately from the classes that use them, they can significantly impact the readability of the code. For this reason, it is advisable to only use extension methods where no other option is viable. You should not use extension methods to modify your own assemblies simply to avoid creating a new version of a library.

Tagged , . Bookmark the permalink.

Leave a Reply