Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can this work (static extension?)

Tags:

c#

I saw this in a answer by Marc Gravell, and I just don't see how it would work

static bool IsNullOrEmpty(this string value)
{    
    return string.IsNullOrEmpty(value);
}

Shouldn't a call to s.IsNullOrEmpty() where s is null, then return a NullReferenceException? How can you de-reference the object to call the function defined here if the object is null?

Or is this some way to end-around monkey patching a static function?

like image 397
Ten Ton Gorilla Avatar asked Dec 10 '22 18:12

Ten Ton Gorilla


2 Answers

Extension methods are magic - they only look like instance methods, but given the extension method:

public static class StaticClass {
    public static void MyMethod(this SomeType obj) // note "this"
    {...}
}

then:

instance.MyMethod();

compiles to:

StaticClass.MyMethod(instance);

And you wouldn't expect that to throw a NullReferenceException - and indeed it doesn't.

This is double-edged. On some levels it is confusing, but it can be really useful. It would be good practice to add your own null-ref check at the start unless you have a reason to allow nulls. Another useful one:

public static void ThrowIfNull<T>(T value, string name) where T : class {
    if(value==null) throw new ArgumentNullException(name);
}
...
void SomeUnrelatedMethod(string arg) {
    arg.ThrowIfNull("arg");
}
like image 120
Marc Gravell Avatar answered Dec 26 '22 17:12

Marc Gravell


Extension methods can be called on null values. A call like this:

bool x = foo.IsNullOrEmpty();

is just translated at compile-time into

bool x = ExtensionClass.IsNullOrEmpty(foo);

No nullity check is performed implicitly. It's very simple syntactic sugar, basically.

While this is odd when you first see it, it's very handy for tests exactly like this. I also have an extension method I like for parameter validation:

x.ThrowIfNull();

which throws ArgumentNullException if x is null.

like image 31
Jon Skeet Avatar answered Dec 26 '22 17:12

Jon Skeet