Extension methods allow for adding methods to existing classes -- sort of. However, they have some limitations that regular methods do not have and some nice benefits beyond what a regular method is capable of. This tip examines those differences as well as when you should and should not use an extension method.
The purpose of this tip is not to explain extension methods at an introductory level, but as a quick summary. An extension method is a
static method in a
static class that has a '
this' keyword in front of the first parameter to specify what type of class it is extending. A simple example shows this quite clearly:
public static class MyExtensions
public static bool IsWellDefined(this string str)
public class Testing
public void DoStuff(string name)
throw new ArgumentException(...)
Drawbacks and Benefits of Extension Methods
Perhaps the biggest drawback to the use of extension methods is that you need to make sure that the
namespace containing the
static class in which the extension method is defined is included in the "
using" clause at the beginning of your file (unless the
static class already resides in the
namespace hierarchy of the class you are working in). When first working with extension methods, this can be confusing, since a method will show up in Intellisense on one file and not another, and even though Intellisense clearly marks that it is an extension method, it can be overlooked.
For many systems, however, this is not a major issue, as often there is some sort of core functionality assembly that is generally a part of each file.
So if you keep all of your commonly-used goodies in the assembly MyCompany.Core.dll, and that assembly is referenced on just about every source code file with "
using MyCompany.Core", then you simply need to put your extension method classes in the
namespace MyCompany.Core and they will practically be available from just about everywhere.
Lack of "ref" Capability
You are not permitted to define an extension method with a "
ref" tag on the same parameter as the "
this" parameter. So you cannot define an extension method that would do this:
public void foo()
int value = 3;
I have not experimented with the new 'ref' features in 7.0 and how they would work in conjunction with extension methods. It might be interesting to see how they interplay.
Third Party Classes
This is a pretty easy one, but you may be using assemblies from third party sources where you don't have the option to modify the classes directly, but you have some simple functionality that is reused in a way consistent with extension method usage (see below), and so the ability to add extension methods here can greatly improve the readability of your code.
It is critical to remember that extension methods are really nothing more than "syntactic sugar", and at compile time, the appropriate
static method is actually called, so all the rules of regular
static method calls apply. In particular, you can deal with
null values. Consider the example above in the Background section. If you were to call
DoStuff(null), you might expect that the "
if" statement would throw an object reference not found exception, but it will not. This is being turned into
if (MyExtensions.IsWellDefined(null)), in which it is perfectly valid to pass in a
null value. The ability to have
null values referenced can lead to all sorts of useful extension methods. For example, I have an extension method in my library called
ToUpperIfNotNull(), which returns
null when the incoming value is
null and translates to upper case when it is not. Similarly, I have an extension method like this:
public static string ToString(this DateTime? dt, string format)
return dt.HasValue ? dt.Value.ToString(format) : null;
In cases where there are frequent
null checks occurring, this extension method syntax can make your code much cleaner.
Reducing Exception Checking / Handling
Throwing exceptions is a natural part of well-written code, but often we have common situations in which we would like to avoid exception handling without complicating our code. Here's a common example. The
string.Substring method will throw an exception if you ever go outside of the boundary regions. So the following will throw an exception:
string newValue = "hello".Substring(0, 10);
Of course, you would never do that directly, but a more generalized usage would be something like this:
public static string GetLeftCharacters(string str, int numChars)
if (str != null && str.Length >= numChars)
return str.Substring(0, numChars);
But since this probably comes up often, a better solution is to turn this into an extension method with just a slight signature change:
public static string Left(this string str, int numChars)
if (str != null && str.Length >= numChars)
return str.Substring(0, numChars);
This brings us back to good old days of VB where we can now do this without ever having to worry about an exception being thrown:
public void DoSomething(string str)
if (str.Left(3) == "ABC")
Another very common problem is the following:
public static void DoSomething(IDictionary<int, string> myDictionary)
string twoValue = myDictionary.ContainsKey(2) ? myDictionary : "defaultValue";
if (!myDictionary.TryGetValue(2, out outValue))
outValue = "defaultValue";
string thisTwoValue = myDictionary.GetValueOrDefault(2, "defaultValue");
GetValueOrDefault extension method above not only is cleaner, but extends the
dictionary using a naming convention similar to what is used elsewhere in .NET, which makes it even nicer.
public static VAL GetValueOrDefault<KEY, VAL>(this IDictionary<KEY, VAL> dict,
KEY key, VAL defaultValue)
VAL val = default(VAL);
return (dict != null && key != null && dict.TryGetValue(key, out val)) ? val : defaultValue;
And this brings me to the last benefit I'm going to discuss about extension methods...
Extension Methods on an Interface
Any purist will tell you that even if C# were to support the concept of putting method definitions into interfaces, it's just wrong, wrong, wrong. Well, in general, I think the arguments are valid, but there are definitely situations where a slight bending of that rule can yield some great benefits.
Case in point is the last example above. Sure, I could define the extension method
GetValueOrDefault on a
Dictionary<KEY, VALUE> directly, but what is gained? Remember that extension methods are syntactic sugar for
static method calls and having method parameters that are interfaces is preferable to concrete classes in almost every case. So having extension methods on interfaces is preferable in many cases to the concrete class equivalent (in my opinion...).
In fact, LINQ is exactly that - extension methods on
How to Use Extension Methods
I really am not going to delve into this topic too deeply, as it's covered elsewhere in great depth, but it suffices to say that an extension method should be a relatively simple extension to your existing classes that has a similar feel and functionality to the existing methods. You should use the same naming conventions as the existing methods both on the method name and the parameters, and it is crucial to add the
/// comments so that Intellisense can help guide the user of your extension method in its usage. If you find your extension method is covering more than one screen, most likely this is not a good candidate for an extension method.
string object, extension methods like "
ToUpperIfNotNull", etc. are all that would be generally considered natural extensions of the
string class. However, an extension method named "
IsAValidPhoneNumber" would NOT be a good candidate for an extension method, and at that point you would correctly realize that you need an external validation class for that.
These Are A Few of My Favorite Extensions...
Over the years, I have developed quite an extensive collection of extension methods. Some of the ones I use most often are shown above. With properly defined extension methods, it becomes so natural that you forget that they aren't built in. Yes, there are plenty of those online, but if there is interest, I could write some articles breaking them down by category. This includes
XDocument, and more.
- 17th November, 2015: Initial version