Saturday, June 14, 2014

I Love C# Extension Methods

If you’re like me, you often find yourself wishing you could perform an operation against an object only to find that the author didn’t implement such functionality.
var cat = new Cat();
Console.WriteLine(cat.Meow());
=> ‘Cat’ does not contain a definition for ‘Meow’ and no extension method ‘Meow’ accepting the first argument of type ‘Cat’ could be found (are you missing a using directive or assembly reference?)
If you’re like me, you’ve probably written a function that takes this object as an argument and then performs the operation.
public static string Meow(Cat cat)
{
        return “meow”;
}
// and then…
Console.WriteLine(Meow(cat));
=> meow
If you’re like me, you find this to be completely ugly. This is no way to interact with objects! Thankfully, C# offers something called Extension Methods1.
public static string Meow(this Cat cat)
{
        return “meow”;
}
// and then...
Console.WriteLine(cat.Meow());
=> meow
Neat, huh? It gets better. See the argument in the method preceded by “this”? That’s the object you’re extending. But it doesn’t have to be a specific object. You could use the magic of inheritance to define the extension method on a base object and have all of its children have it.
public class Lion : Cat {
        //...
}
// and then...
var lion = new Lion();
lion.Meow();
=> meow
You can also do this on interfaces.
public interface ICat {
        string Says { get; }
}
public class Cat : ICat {
        string Says
{
get
{
        return “meow”;
}
}
}
public class Lion : ICat {
        string Says
        {
                get
                {
                        return “roar”;
                }
        }
}
// then define the extension...
public static string Meow(this ICat cat)
{
        return cat.Says;
}
// and then...
var cat = new Cat();
var lion = new Lion();
Console.WriteLine(cat.Meow());
Console.WriteLine(lion.Meow());
=> meow
roar
This is somewhat pointless, though, if you’re the one implementing the classes. It gets more power when you’re playing in someone else’s yard. For example, let’s say you want to encrypt a list of strings. You could use the ugly version:
List<string> secretWords = new List<string>();
foreach (string secretWord in GetSecretWords())
{
        secretWords.Add(Encrypt(secretWord));
}
Or the more appealing LINQ version:
List<string> secretWords = GetSecretWords().Select(
s => Encrypt(s)
);
Or you could define an extensions and use magic!
public static IEnumerable<string> Encrypt(this IEnumerable<string> list)
{
        return list.Select(s => Encrypt(s));
}
List<string> secretWords = GetSecretWords().Encrypt();
(Note that I used IEnumerable<T> instead of List<T>, because List<T> extends IEnumerable<T>, and I like to encourage people to make use of IEnumerable<T>, because you’re less likely to get out of memory exceptions if you use it instead of lists and arrays)
If you wanted to go crazy, like I often do, you could even extend the string class to have an encrypt function:
public static string Encrypt(this string str)
{
        return Encrypt(s);
}
// then you could modify IEnumerable<string>.Encrypt()...
public static IEnumerable<string> Encrypt(this IEnumerable<string> list)
{
        return list.Select(s => s.Encrypt());
}
Some people may argue that this is purely “syntactic sugar”, and while it may be, it does provide for a cleaner code base. Instead of writing Method(object) for some void method that transforms the object, you could write object.Method(), which not only looks a lot neater, but also makes it more apparent to downstream coders the intent of the method (especially if it transforms the object).
It’s also handy for adding features to third party objects that the maintainer didn’t include. This has a variety of applications, including specialized extensions (e.g., advanced math extensions to numeric objects or esoteric list operations). It’s even nice to use in an MVC app, keeping your model definitions free of methods.
I use extensions in just about every development project I work on. They’re an idiom of my coding style. I like the way they help communicate to the hu-mans working on the code my intents, and I like how they make the implementations of everything look a lot cleaner. Combined with LINQ, they can be a powerful ally.
I would recommend that if you’re making use of extension methods, you also implement unit tests for these, especially if you’re extending a third party library. If the maintainer ships a version with the same signature, you might not realize, and it might have different behavior. A few unit tests would at least ensure consistent usability.
My biggest wish w.r.t. this is that Microsoft will release extension properties, and static class extensions.
I’m curious what you think about extension methods. Love ‘em? Hate ‘em?

No comments: