I was having a conversation with a programmer new to C# recently, who was rather confused by something similar to the following bit of code. He'd been looking at the source for a library on GitHub, and he didn't understand why this could run without errors:
Widget widget = null; // do stuff that may or may not assign an object to widget widget.DoSomething();
To him, it seemed to be risking a
NullReferenceException
, as you can't call a method on a null object.
Ordinarily this is true, but as I found myself explaining, there is one scenario where this code will run quite happily: When
DoSomething()
is
an extension method.
Extension methods are not methods on the class you are referring to, they are static methods defined elsewhere in separate static classes. (Hence the name - they are a way of extending the behaviour of other classes or interfaces) And the reason why they can deal with null objects is that their code takes the object in question as a parameter. The definition looks like:
public static class Extensions { public static void DoSomething(this Widget widget) { // do something with the widget } }
The
this
keyword is marking the declaration out as an extension method. And hence the compiler is transforming the original
widget.DoSomething()
statement into a static method call
Extensions.DoSomething(widget)
behind the scenes. Hence when
widget
is null, you don't get a crash unless the code inside your extension method does something that causes it.
The most commonly used extension methods are probably those provided by the Linq framework to do things like add filtering behaviour to all enumerables. But the other common pattern I see (and the source of confusion for the dev I was talking to) is helping to standardise behaviour for handling parameter or object validation. Things like:
public static class ExampleExtensions { public static void CheckParameterForNull<T>(this T obj, string parameterName) where T : class { if(obj == null) { throw new ArgumentNullException(parameterName); } } public static bool IsNullOrWhiteSpace(this string str) { return string.IsNullOrWhiteSpace(str); } } public class MyClass { public void MyMethod(Widget widget, string text) { widget.CheckParameterForNull("obj"); if(text.IsNullOrWhiteSpace()) { // do stuff } // do the rest of the method } }
As the question which started me thinking about this suggests, you need to be a bit careful applying this pattern though. Because the idea of "calling a method on a null object" is normally an error pattern in .Net (and many other languages) it's important to balance the confusion this might cause against whatever benefits the extension method itself can provide. The long term benefits of clear and readable code can outweigh the short term benefit of a clever pattern.
You also have to be a bit careful about the namespaces of your extension methods. You only get intellisense for them (and the code will only compile) if the namespace you declare the static extension class in is included in your current scope – most likely via a
using
statement. Another source of confusion to up and coming developers is when they start a new file for a class and suddenly a collection of methods on the objects they're working with have "disappeared". While it's a simple fix to reference the correct namespaces, it can be frustrating if the extension classes are defined in unintuitive places in the codebase.
What was it Spiderman said about power and responsibility?
↑ Back to top