This post was published in .NET Magazine. I recently did a talk at the SDC Conference at Papendal, Arnhem, discussing this topic.
As you’re probably have been made aware of in abundance, in .Net 3.5 Microsoft introduced a little language feature called LINQ. Although LINQ has been demonstrated at all major and minor conferences, the way LINQ executes queries on already existing types remained slightly less apparent. To this means LINQ introduces a number of new query operators, using yet another new language feature called an extension method.
Basically, there are two sets of LINQ query operators. One set that operates on objects of type IEnumerable and another set that operates on objects of type IQueryable. To implement the methods in these sets, the .NET architects chose to add something called extension methods, and write the required methods as extension methods to the Enumerable and Queryable classes, instead of directly extending these classes – which would seriously pollute the .NET framework.
Defining a simple extension method
Apart from the apparent use of these extension methods in the query operators of LINQ, there is slightly more to it. At first sight, extension methods appear to allow you to extend any class in any namespace with additional functionality. Let’s have a closer look at them by using an example.
One of things I always disliked about working with the DataSet class is that to obtain the value from a column in a row in a table, I’d have to write code that looks at lot like this:
This code is both tedious and poor code however, as it doesn’t do any check on whether the table and row are actually available. As you’ve probably all have written code like this before, you would probably have appreciated a method like Get() on the DataSet class, like I’m using in the following code example, where Get() performs all necessary checks and formatting.
The issue here is that you cannot extend the .NET framework class DataSet to encapsulate this functionality. This is where extension methods come in neatly. With .NET 3.5 I can now write a method such as the following.
If you’ve never seen an extension method before, the first parameter will appear strange to you. The this keyword is added to it to show that this Get() method works on the DataSet class. Although this method is defined as a static method on a class called DataSetExtensions, it is recognized as an instance method on the DataSet class.
Intellisense even recognized my method, and the code comments I’ve added. The only difference between an instance method and an extension method from an intellisense point of view, is that you’ll still be able to notice the this parameter in the signature of your extension methods. Of course, the same goes for .NET framework defined extension methods, like the LINQ Where() method, which also displays the this parameter.
Extension methods and the Open Closed Principle
Doesn’t that look cool? I think so. When I first read about extension methods I immediately thought of a whole bunch of functionality that I could add not only to our own frameworks, but also to open source and even the .NET framework itself. But before bloating out lots of code, let me give you some caution.
My biggest worry was whether extension methods would allow me to break existing framework code. There’s a well known principle that needs to be examined here, which is called the Open Closed Principle (OCP). In short, this principle states that classes should be open for extension, but closed for moderation. In general I think this is a principle well worth living by. So, the big question is: do extension methods allow me to change the behavior of existing classes? What happens if I write an extension method, such as the one below?
The question is, by writing this simple extension method, did I just override the ToString() method for all classes in my applications? Surely, such extension methods would kill a lot of projects really fast. Of course the .NET architects do not allow you to do so. There’s thing or two you should know about how extension methods work, and about how they are compiled.
Compiling extension methods
First, they’re defined within the context of a namespace, Extensions in the example above. To use an extension method on a class in your code, you will need to add a reference to the namespace that contains the extension methods. Without this reference, the method don’t even show up.
Second, and even more important, extension methods are in fact just static methods on a static class, as can be seen in intermediate language (IL). Extension methods only appear in your code editor as instance methods on the target class. The fact that they’re defined as static methods outside of your target class means that in an extension method you can only get to the public properties the target class exposes, but you will not be able to reach the protected and private fields of this class, nor will you be able to define new properties or fields.
Even more important, it is interesting to notice what the compiler does with your extension methods, especially in the case that you would define a method with the same signature as the method in the target class, like with the ToString() method above.
The compiler follows a straightforward rule: extension method always have a lower priority that real instance methods. As a consequence, when the compiler tries to resolve a method invocation it first looks in the target class for methods with matching signature, and consequently in its ancestors, and bind to this method if located. Only if no instance method is found, will it start to look for extension methods with the same signature. Following this convention the ToString() method I’ve defined above will never be called, as the object class defines a method with a matching signature.
Even when I try to create a (very stupid) extension method like the one below, targeting the Equals(string s) method just for matching with a string, the compiler will still bind to the Equals(object o) method from the object class, even if it has a wider scope – it compares with an object, not a string.
This compiler directive satisfies my concerns. Using extension methods, you will not be able to alter any existing functionality. You can not override existing methods, nor get a hold of private or protected fields. In fact, the extension method totally live outside of the target class. So, you’re quite safe.
No worries then?
Well, there’s something else that concerns me about extension methods. The most demo’s I see on extension methods worry me. There seems to be no end to people extending the String class. I’ve seen demo’s that check whether a string is a valid email address, a valid URL, and even extensions that speak out a string using a synthesizer – although I expect good craftsmanship, not really something I long for in my applications.
It’s just that stuff like this should not be extensions to the string class. Unless at least 50% of all strings you use in your code are in fact email address, I would consider a different pattern here, such as defining value objects of type Email, Zip or whatsoever. In general, my concern with extension methods is that it’s such a neat little technology, that it will invite people to use it for all the wrong reasons – just because it’s fun to define an extension method for instance.
Before you know it, the developers in your project will have defined loads of extension methods, to all kinds of framework classes. You should be well aware of the possibilities this offers to break your application architecture and create lots of undesired dependencies. Just take a quick look at the following example.
Here, I’ve added an extension method to the CodeActivity class, which resides in the namespace System.Workflow.Activities. Now my Extensions namespace has a dependency on this namespace, and moreover, also on the underlying System.Workflow.ComponentModel namespace.
However, my previous code example where I extended the DataSet class also resides in my beautiful Extensions namespace. So from this day forward, every time I use my Get() extension method for DataSet, I’m indirectly also connected to the workflow namespaces. Just as an example.
Furthermore, when you define an extension method to extend a type delivered by a framework, you also run the risk that your extension method will cause your code to break if the implementation of that type changes, or if your project migrates to a newer version of that particular framework, of .
Extending framework base classes
On the good side, you will more likely use extension methods that other developers have written, than define your own. Here, extension methods are a powerful features, as applying extension methods does not require any additional knowledge. Most extension methods will be written by frameworks developers, who now will feel enabled to solve anomalies. Or even more likely by developers who feel the need to extend base classes from existing frameworks, both from Microsoft and open source, such as in the following example, that extends the open source frameworks CSLA.
One of the most reused base classes in the CSLA framework is called BusinessBase. It serves as layer supertype for all domain objects in applications built with the framework. The BusinessBase class has the ability to validate its business rules. To this means it stores a broken rules collection that contains references to business rules that are violated during a validation of your domain object.
In some cases, for instance when displaying violated business rules on screen, it can be handy to know which business rules were broken per property. The BusinessBase class however, does not have this ability.
The code example here displays an extension method for BusinessBase that loops through the total collection of broken rules using a LINQ query that filters the broken rules for the selected property (using the property’s name). This method is very useful and powerful example of how developers can tweak the functionality of framework classes. It should come as no surprise that many more such extension methods will become available from the community soon for popular frameworks such as Microsoft’s Enterprise Library, nHibernate, ADF, CSLA and of course for the .NET framework itself.
Handle with care
Extension methods are a language feature that does not really stand out in the crowd, but can be very useful, especially to avoid repetitive work that should have been a feature of frameworks you apply to your projects. However, when developing extension methods you will need to be very aware of the side effects described above. I therefore recommend to implement extension methods sparingly. Under normal circumstances, you will still extend existing types by inheriting from them, even though this requires your developers to use your new class by convention instead of an extended base class. To leave you with a proper quote: “Creativity is a natural extension of our enthusiasm.”