Implementing Extension Methods in C# (
Page 1 of 3 )
Extension Methods are a way of extending an existing class without deriving a new class. In this article, Paul Kimmel shows you how to use extension methods in C#.
Introduction
The .NET Framework employs the concept of sealed classes. A sealed class is a class that cannot be inherited from. But, what if we (or Microsoft) want to extend these classes? Based on the meaning of sealed it’s not possible. Compound the technical inability to extend sealed classes with classes that are defined as the result of a LINQ query, called projections, and there is no opportunity to extend.
Another desire that class designers have is to avoid deep inheritance trees. Generally using inheritance to add a capability or two is undesirable because it leads to deep inheritance trees that are difficult to comprehend and maintain.
To overcome some of these challenges Microsoft introduced the extension method. Extension methods are defined in separate static classes as static methods and the first argument of the method is the extended type. The extended type—the first argument—is modified with the keyword this. Although an extension method is a static method in a static class, extension methods have member method semantics. That is, extension methods are called is if they were a member of the extended class, a regular member method.
Writing an Extension Method
On the surface extension methods are easy to write. Define a class with the static modifier. Define a method with the static modifier, and the modify the first parameter—the type you want to extend—with the this keyword. Write the lines of code. For the most part this is all one need do. However, as with everything else there are some boundaries involved, and they are listed here for completeness.
Can extend sealed types and non-sealed types without inheritance
Reduce deep inheritance trees when just one or two new behaviors are needed
Extension methods are static methods in static classes
Multiple arguments are allowed but first argument is modified with this
Properties, events, and operators cannot be extended (right now)
Extension methods follow instance methods in compiler resolution priority and can co-exist with instance methods with the same signature
Extension methods use instance method semantics
Supported by Intellisense
Generic extension methods are supported
Extension methods can be invoked on literals like “Hello World”.method or 1.method
Extension methods can be used on sealed classes and intrinsic types like string
An extension method is not a true member so an extension method can only access public members of the extended type
In VB.NET the ExtensionAttribute is used literally, but its implicit in C#
The term associated with extension methods is duct typing.
Listing 1 shows an extension method that uses Reflection to send the property values of an object to a TextWriter stream. In SimpleExtensionMethod an array of integers is assigned to the anonymous variable numbers. A LINQ query is invoked to create a new anonymous type from the number indicating the value and the number’s parity—odd or even. Finally the result of the query calls the extension method Write, sending the property name and value for each object to the console.
Listing 1: An extension method that displays the state of an object using new features of .NET and Reflection.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Data;
using System.Data.SqlClient;
namespace ExtensionMethod
{
class Program
{
static void Main(string[] args)
{
SimpleExtensionMethod();
}
public static void SimpleExtensionMethod()
{
var numbers = new int[]{1,2,3,4,5,6};
var oddsEvens = from num in numbers
let parity = num % 2 == 0 ? "Even" : "Odd"
select new {Number=num, Parity=parity};
foreach(var obj in oddsEvens)
obj.Write(Console.Out);
Console.ReadLine();
}
public static class WriteObjectState
{
// extension method that writes an object's state
public static void Write(this object obj, TextWriter writer)
{
var formatted = from info in obj.GetType().GetProperties()
let value = info.GetValue(obj, null)
select new {Name=info.Name, Value=value==null?"":value};
Array.ForEach(formatted.ToArray(), r=>
writer.WriteLine(r));
}
}
}
The extension method Write in the static class WriteObjectState extends object and accepts a TexTWriter, for example, Console.Out. The Write extension method uses a LINQ query to select and iterate through all of the object’s properties and project these aspects of a property to a new type. The Array.ForEach method iterates over each property name and value pairing and sends these to the writer (the console).