Extension methods are an integral part of modern .NET and some of .NET’s best features such as LINQ. Unfortunately, a lot of developers get intimidated by them and don’t understand what’s going on under the surface or how to build new ones. In this article I’ll attempt to demystify extension methods and illustrate how they can be used to build elegant and fluent code.
The Basics: Static Methods
In order to discuss extension methods, we have to first discuss static methods.
A static method is simply a method declared with a static
keyword. This tells .NET that the method operates not on a specific instance basis, but is attached to the class as a whole. Since these methods are static, they do not have access to the state of any specific instance unless it is passed in as a parameter to the method (more on this later).
The Integer.Parse
method is a fairly well-known static method as is String.IsNullOrEmpty
.
Over the course of this article we’ll be building out a method for getting information on books, so let’s create a static method that builds a list of books.
Now, to call out to get our books, we just do something like this:
var books = Books.GetBooks();
Pretty simple to use.
Extension Methods
Next let’s turn our attention to extension methods.
Put simply, extension methods are specially declared static methods that the compiler lets you call on objects matching their signature.
Let me show you what I mean.
Let’s say we have the following static method:
Here we can take any Book
instance and pass it in to Books.IsBoring
and get a boolean response.
Let’s change this to be an extension method.
Since extension methods can only be declared in static classes (classes which cannot be instantiated and have only static members), we need to add the static
keyword to our class.
Now, we declare our IsBoring
method to be an extension method by adding the this
keyword to the first parameter like so:
What the this
keyword is telling .NET is that IsBoring
is an extension method and can either be invoked via the static method syntax like Books.IsBoring(someBook)
or via an extension method syntax like someBook.IsBoring()
.
Note that the this
keyword in the extension method syntax can only be used for the first parameter, which is the type or interface that the method extends.
Extension methods are syntactic sugar to have the compiler replace extension method style invocations to static method invocations.
The net result, however, is that extension methods let you appear to bolt on new functionality to other classes or interfaces. This is their primary advantage as extension methods allow you to simplify calling syntax at the cost of obscuring exactly where the method is declared to the casual reader.
Now that we know what extension methods are, let’s look at using them to build a fluent syntax or domain specific language.
Chaining Extension Methods Together
Let’s say you want to create a book and need to perform a number of operations in order to create a valid book. If you wanted to offer a fairly flexible and readable API, you could use extension methods to create a mini domain specific language (DSL).
In this example, our end goal is to create a book object that is customized based on the values we’ve configured.
Let’s focus on the end result first:
There’s a lot going on there, but maybe not as much as you think.
Let’s start with the Books.CreateBook
call. This is a static method invocation that takes in a string representing a book’s title and return’s some mystery object.
Let’s call that object a BookBuilder
and say that it looks something like this:
Okay, now this is making maybe a little more sense. That’d mean that our CreateBook
static method would look something like:
Next our example has us calling WrittenBy
. Well, the BookBuilder
class doesn’t define that method. In a normal application we’d probably just add the method to BookBuilder
, but that wouldn’t let us play with extension methods here, so let’s pretend that the BookBuilder
class is defined by some code we don’t control and can’t modify.
We’ll handle the WrittenBy
method by adding an extension method:
This is a very simple method, but there’s some key things going on here.
First, the method acts as an extension method on BookBuilder
instances due to the this
keyword in the parameter signature.
Second, the method is invoked with only one parameter specified (e.g. WrittenBy("Michael Crichton")
because the first parameter is inferred based on the BookBuilder
you’re invoking the extension method on.
Third, we’re returning the same builder instance we got back. The reason why we return this parameter is entirely to support fluent syntax like we saw in the example earlier, and allow invoking extension methods on the return result of prior extension methods.
The final static class might look something like this:
That might not look like the prettiest code you’ve ever seen, but the type of syntax it can create can be incredibly powerful and beautiful.
Let’s Talk about LINQ
Extension Methods were added to the C# language explicitly in order to support L anguage In tegrated Q uery (LINQ) in .NET Framework 3.5.
LINQ is one of my favorite features of C# in terms of developer productivity, and none of that would have been possible without extension methods.
LINQ lets you do things like:
Maybe this is a little bit of a silly example, but this all works by having extension methods that take in IEnumerable<T>
or IQueryable<T>
and use various Func
signatures to filter, sort, or transform the collection.
Put another way, if you really wanted to, you could write your own version of LINQ with about the exact same syntax using extension methods. Please don’t do this – Microsoft did a great job already – but the capabilities of extension methods allow you to do this.
Closing Thoughts
Hopefully this demystifies some of the magic behind extension methods, LINQ, and static vs instance methods.
I am convinced that extension methods (and LINQ by extension) are one of the key productivity gains of .NET technologies, alongside things like the base class library, the common language runtime, Visual Studio, and generics.
While you may not create or even think about extension methods, they power a lot of what we do in modern .NET and the flexibilty they offer can be a tool for good.
The post Using Extension Methods in C# to Build Fluent Code appeared first on Kill All Defects.
Top comments (12)
Great article but what do you think about the allocations caused by LINQ?
As a game programmer I've been taught to avoid using LINQ, especially in scripts running in real-time on the main thread in order to avoid allocations and so sudden frame drops caused by the GC kicking in. Surely a game is not comparable to other types of programs and besides not every LINQ method necessarily allocates (I sincerely don't know). Maybe some of the allocations could be even avoided, like those caused by the Func passed by simply caching them, but then it would lose in readability.
It's a tool like many others .NET put you at your disposal but would you still suggest it for environments like games?
I use LINQ by default. However, I did find while profiling a roguelike's core AI routines that LINQ significantly added to the duration of the application. However, this was a core routine in a genetic algorithm that had to run millions of times.
My suggestion would be to go with LINQ until your data tells you to avoid it in key places, then make those optimizations.
(I emphasised the main purpose)
It's a very valid question. The answer is "I need to teach extension methods". If you have full control of all code, you're better off putting it in
BookBuilder
.Nice post.
I’m a fan of the Extension methods. Like in your examples, I combine them with the Builder pattern too. I think that this combination creates a readable Domain Specific Language (DSL) that could be used in the test case scenarios for an application. With such a DSL, we can build our System Under Test (SUT) in a very descriptive way.
I can't wait for your next article.
Cheers.
I've done that before and really like the power and simplicity of that, plus the way it makes tests more maintainable. I really should write about that at some point soon.
Great post Matt. Clearly explained and absolutely useful!
Cool! This article further solidifies my love for the Builder Design Pattern. It's one of the best ones out there, to be honest.
Thanks for the introduction to Extension methods. You packed some great information in there and in a easy to follow and understand way.
Slowly slowly languages incorporate more Smalltalk features and style.. and still fail to be as clean and expressive.
If you're ready to take it unto the next level, check out how you can use extension methods in some more creative ways.