Extension Methods
It is quite common for programmers to write a method/function in their
application which is applied to a basic object. Good OOP style might dictate
that we would build the method into the class. For example, we might have a
string which is holding a UK postcode, we would write function to check if it is
valid. The first attempt to OOPify (sorry!) this might look like this:
public class UKPostCode {
public string PostCode { get; set; }
public bool isValid() {
bool result = // some code to check actual postcode??
return result;
}
}
...
UKPostCode postcode = new UKPostCode { PostCode = TextBox1.Text };
if (postCode.isValid())
{ doSomething(); }
else
{ reportError(); }
This works, but it requires us to take our basic string property and package it
up into an object. Wouldn't it be great if we could extend the definition of the
string class to include a method such as isValidPostCode? Extension methods do
just this. If we create such an extension method for the string object we can
use code such as follows:
if (TextBox1.Text.isValidPostCode())
{ doSomething(); }
else
{ reportError(); }
This is a much cleaner solution to the problem. So what does an extension method
look like? Unfortunately, it is a rather obscure piece of syntax, but the power
it yields is worth the effort in getting to understand it. An extension method
is a static method of a static class and the method has to indicate the object
type which it is extending. In the case of our postcode problem, we would need a
class as follows:
public static class MyStringExtender
{
public static bool isValidPostCode(this string postcode)
{
Regex pcodevalidator =
new Regex(@"^([A-PR-UW ... 2}|GIR 0AA)$"); // trimmed
return pcodevalidator.IsMatch(postcode);
}
}
The only thing which distinguishes this class as an extension method, rather
than a utility class with some helper methods is the use of the keyword 'this'
before the first parameter. This tells the compiler that it can use the method
with an object of the same type as the parameter. We must of course put a
'using' statement in our code to allow the compiler to find the class and its
extension method(s) when we use it. Once this is done the intellisense/code
completion feature in Visual Studio will include our new method in the list of
methods while we are typing our code.
Our extension methods can include extra parameters which would allow us to write
more complex extensions, for example:
Location loc = myGPS.GetLocation();
if (TextBox1.Text.isCloseTo(loc)
{ Label1.Text = "Getting close"; }
else
{ Label1.Text = "Not quite there yet!"; }
The extension method would look like this:
public static class MyStringExtender
{
public static bool isCloseTo(this string postcode, Location loc)
{
double distance = // write code to work out distance between
// current postcode and the GPS location
return distance < 100; // metres
}
}
You can even use extension methods on literal values too, for example:
bool nearlyAtWork = "CH1 4BJ".isCloseTo(myloc);
The power of extension method is demonstrated by the build in libraries for
querying in the System.Linq namespace. The methods in this library provide built
in methods allowing you to query a range of data structure, most importantly
structures which implement the IEnumerable interface, such as Lists and Array
types.
Built in LINQ extension methods
If you include "using System.Linq;" in your code file you can make use of built
in extension methods for a range of data structures. These extension methods are
particularly important for the developer as they allow you to use a consistent
syntax for accessing and organising resulting data across a range of data types,
e.g. SQL, XML, arrays etc.
Take for example our list of Books. We can use the LINQ extension methods to
perform a range of manipulations on the data. There are methods such as:
- Average
-
To return the average value of some data field in a collection of objects
- Max (or Min)
-
To return the maximum (minimum) value of some data field in a collection of
objects
- Where
-
To return a subset of a collection of objects, based on some criteria
Distinct extension libraries are available which target different kinds of data,
for example Linq to SQL and Linq to XML. Each library includes domain specific
extensions, e.g. the Descendants method returns a list of XML elements which are
the immediate descendant of a given XML node element.
To make use of these extension methods you need to be familiar with another new
feature in C# - Lambda expressions - although it is possible to manage without
them, except it require more coding and more complex syntax.