
Extension Methods
May 30, 2008In my series on the new C# features, I had previously blogged about -
- Implicitly Type Local Variables,
- Object Initialization,
- Anonymous Types,
- Auto Implemented Properties, and
- Implicitly Type Arrays
In this post, I will be talking about Extension methods. Extension methods allow new methods to be added to an existing class without having to actually extend the class using inheritance.
For instance, if you wanted to add a function called ReverseString to the String class, you can add it without creating a new class that inherits from String. Of course, String being a sealed class cannot be extended and adding a function to it is not possible via inheritance.
The syntax for doing this looks like this -
public static string ReverseString(this string str)
{
//code to reverse the string
}
Notice that the function has to be static and it takes this followed by the type to which the extension method needs to be added to as the first parameter.
Intellisense
Once an extension method has been created, it shows up in Intellisense – which is quite handy.
Notice that the icon for an extension method is different to the usual ones.
Usage Rules
When using extension methods, there are few rules that need to be followed -
- Extension methods have to be declared in a static function in a top level static class
- The first parameter has to start with “this” and it cannot appear multiple times in the parameters
- The keyword “this” must be followed by the type that needs to be extended. The type can be an interface, abstract class, a concrete class or even a sealed class.
- You cannot use things like “ref” and “out” with “this”
- You cannot extend Properties, Events or operators (something for the future version, perhaps
?)
Ambiguity
If you have the same extension method declared in two separate static classes, then the compiler will throw an error message saying that the call is ambiguous when the actual function is called in code. Unlike namespaces that help resolve classes that share the same name, there is no way to resolve function name clashes.
Extension methods that currently exist
.NET framework 3.5 comes loaded with a lot of extension methods. For instance, the IEnumerable interface has extension methods such as Aggregate, Average, Concat, Count, GroupBy, etc. A lot of these extension methods are essential for implementing LINQ (which will be covered in a future post).
More Examples
Extension methods can have additional parameters, as this example shows -
public static string ExtensionMethodWithParameter(
this string str,
string value)
{
//Do nothing, it is just an example
return str;
}
You can also add extension methods to arrays -
public static float MyAverage(this int[] intArray)
{
float sum = 0;
foreach (var element in intArray)
{
sum += element;
}
return sum / intArray.Length;
}
They can also be added to the base class of them all – “object”. For example, this function converts any object into an Xml representation, based on its properties -
//Simple, shallow implementation. Converts any object to Xml
public static string ToXml(this object o)
{
Type myType = o.GetType();
XmlDocument xmlDoc = new XmlDocument();
XmlDeclaration xmlDeclaration = xmlDoc.CreateXmlDeclaration(
"1.0", "utf-8", null);
// Create the root element
XmlElement rootNode = xmlDoc.CreateElement(
XmlConvert.EncodeName(myType.Name));
xmlDoc.InsertBefore(xmlDeclaration,
xmlDoc.DocumentElement);
xmlDoc.AppendChild(rootNode);
var properties = myType.GetProperties();
foreach (PropertyInfo prop in properties)
{
XmlElement childNode =
xmlDoc.CreateElement(prop.Name);
childNode.AppendChild(
xmlDoc.CreateTextNode(
prop.GetValue(o, null).ToString()));
rootNode.AppendChild(childNode);
}
return xmlDoc.InnerXml;
}