Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should one always write null-proof extension methods in .NET?

Imagine we have defined a an extension method that takes this form:

public class Foo
{
    public void Bar(int arg) { ... }
}

public static class FooExtensions
{
     public static void Baz(this Foo @this)
     {
         @this.Bar(0);// not null-proof
     }
}

Here we are exposing a public extension method Baz on the Foo class (the example is trivial). Now if we have the following usages:

Foo foo1 = null;
foo1.Bar(0); // throws NullReferenceException

Foo foo2 = null;
foo2.Baz(); // again throws NullReferenceException

So the code in both cases will behave consistently - regardless of calling a member method or extension method we will get the same NullReferenceException() thrown. This makes me feel there is something amiss in the situation. My thoughts are:

  • Code that allows NullReferenceExceptions is poor, as per most guidelines. The extension method is an example of such bad practice. In order to comply to guidelines and expose a failure-proof code as a public API should be, there must be made some null-safety checks like this:
    public static void Baz(this Foo @this)
    {
        if (@this == null) 
        {
            throw new ArgumentNullException("@this");
        }
        @this.Bar(0);
    }
  • Consistency in the behavior will allow the developer to easily detect the null reference situation, since both cases behave the same. I mean, calling an extension method is not always obvious to the coder, so if the line foo2.Baz() threw a NullReferenceException it is evident that foo2 is null.

The above contradiction lead me to some conclusions. The second point misses an important concern - the stack trace. In a standard NullPointerException case, the stack trace leads to the foo1.Bar(0) line directly. In the extension method, it will point to the line from within the extension method where the exception is thrown. So, the consistent behavior still has an inconsistent stack trace.

And now the question - regarding null-safety, how do "best practices" apply to extension methods that are going to be used by third parties? Should we disregard the consistency by adding argument null-proof validation on the @this parameter always? Or is it a corner case that can have us bypass the good practice advices?

Edit

I am addressing a situation where a library with the extensions will be exposed. It will not use non-built-in/3rd party solutions like PostSharp or other similar techniques. Also full compatibility with .NET 3.5 is desired.

like image 690
Ivaylo Slavov Avatar asked May 10 '13 13:05

Ivaylo Slavov


2 Answers

It depends on how you view extension methods. Given that they are merely syntactic sugar on top of a regular static method, I would say that they should follow guidelines for static methods - check all arguments including the this parameter.

This is particularly applicable if you have extensions specifically to handle null - I am aware it is not the preferred use of extensions for most people, but I relish methods like the following:

public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> source)
{
    return source ?? Enumerable.Empty<T>();
}

public static void DisposeIfNotNull(this IDisposable source)
{
    if (source != null)
        source.Dispose();
}

Obviously the parameters must be permitted to be null for these methods to work.

like image 138
Alex Avatar answered Sep 30 '22 05:09

Alex


When I have a problem like this within my organization, I default to convention.

Anyone who has an opinion on this knows what they are talking about. It just depends on whether they look at extension methods from the instance or static side.

I have used WWLD (What would LINQ do?) before since it is a common library that uses extension methods that most .NET developer are used to.

Example Code:

IEnumerable<int> test = null;
test.Where(t => t > 0); // throws an ArgumentNullException

So no matter what my opinion is, I would use ArgumentNullException as that is what other .NET developers would be used to.

like image 20
Nick Freeman Avatar answered Sep 30 '22 04:09

Nick Freeman