17

You all do this:

public void Proc(object parameter)
{
    if (parameter == null)
        throw new ArgumentNullException("parameter");

    // Main code.
}

Jon Skeet once mentioned that he sometimes uses the extension to do this check so you can do just:

parameter.ThrowIfNull("parameter");

So I come of with two implementations of this extension and I don't know which one is the best.

First:

internal static void ThrowIfNull<T>(this T o, string paramName) where T : class
{
    if (o == null)
        throw new ArgumentNullException(paramName);
}

Second:

internal static void ThrowIfNull(this object o, string paramName)
{
    if (o == null)
        throw new ArgumentNullException(paramName);
}

What do you think?

Sam
  • 7,252
  • 16
  • 46
  • 65
AgentFire
  • 8,944
  • 8
  • 43
  • 90

7 Answers7

13

I tend to stick to the ubiquitous Guard class for this:

static class Guard
{
    public static void AgainstNulls(object parameter, string name = null)
    {
        if (parameter == null) 
            throw new ArgumentNullException(name ?? "guarded argument was null");

        Contract.EndContractBlock(); // If you use Code Contracts.
    }
}

Guard.AgainstNulls(parameter, "parameter");

And shy away from extending object, plus to the naked eye a method call on a null object seems nonsensical (although I know it is perfectly valid to have null method calls against extension methods).

As for which is best, I'd use neither. They both have infinite recursion. I'd also not bother guarding the message parameter, make it optionally null. Your first solution will also not support Nullable<T> types as the class constraint blocks it.

Our Guard class also has the Contract.EndContractBlock() call after it for when we decide to enable Code Contracts, as it fits the "if-then-throw" structure that is required.

This is also a perfect candidate for a PostSharp aspect.

Adam Houldsworth
  • 63,413
  • 11
  • 150
  • 187
  • I'm in two minds about this; I think I prefer Jon Skeet's explicit NonNullable contract as that makes it explicit at creation time that I never want T to be nullable, whereas I might forget Guard.AgainstNulls, or it might be hidden inside another method or similar. Agree totally with your PostSharp aspect though, so +1 + -0.5 + 1 (with Math.Floor thrown in) results in... +1 ;-) – dash Jul 17 '12 at 12:18
  • 1
    I think @AgentFire meant NotNullable. On the other hand, some people just prefer Extension syntax over explicit method calls. – dash Jul 17 '12 at 12:23
  • @dash If something is so important that it should be baked into a contract for it, then there should likely be a test for it too - meaning that if you forgot to guard against nulls, the test would also remind you. – Adam Houldsworth Jul 17 '12 at 12:24
  • If only everyone wrote tests for every possible usage :-) I do actually think NotNullable is more explicit - I've decided, when creating this that it's never going to be null, whereas Guard.AgainstNulls is I've created something but then I need to remember that I never want it null; it's largely a semantic difference, and I did like your answer! There's definitely an element of coding style there too, though. – dash Jul 17 '12 at 12:26
  • @dash The only reason I wouldn't is because of the shear number of things that cannot be null when you need to use them. The main difference in my opinion is that something like this struct stops them from being null **at all**, whereas testing just means they cannot be null prior to use (but can otherwise be set to null elsewhere). – Adam Houldsworth Jul 17 '12 at 12:29
5

I'd use internal static void ThrowIfNull<T>(this T o, string paramName) where T : class. I won't use internal static void ThrowIfNull(this object o, string paramName) because it might do boxing.

Vasile Mare
  • 189
  • 9
  • 1
    The only downside with that choice is you won't be able to test `Nullable` items. – Adam Houldsworth Jul 17 '12 at 12:18
  • @AgentFire From the compiler: "The type 'int?' must be a reference type in order to use it as parameter 'T' in the generic type or method" in VS2010, so something has changed. – Adam Houldsworth Jul 17 '12 at 12:22
  • 1
    Why would you test for null a Nullable in this context? If there is such a need then the function needs redesign – Vasile Mare Jul 17 '12 at 12:23
  • @AgentFire Framework 4.0 also, but this would be a compiler. Vasile yes true, but I was just stating it because they can technically contain null. – Adam Houldsworth Jul 17 '12 at 12:25
  • 2
    The impact of boxing is also negligible, people forget it is actually quite optimised from .NET pre-generics days. Though it can increase GC pressure. I tend to find "boxing" isn't a valid catch-all excuse these days, boxing is perfectly acceptable in some circumstances and not in others. – Adam Houldsworth Jul 17 '12 at 12:38
5

As of .NET 6, now we have the static method ThrowIfNull in the System.ArgumentNullException class with the following signature:

ThrowIfNull(object? argument, string? paramName = null);

Therefore, instead of writing:

if (value == null)
{
    throw new System.ArgumentNullException(nameof(value));
}

Now we can simply write:

System.ArgumentNullException.ThrowIfNull(value);

The docs: https://learn.microsoft.com/en-us/dotnet/api/system.argumentnullexception.throwifnull?view=net-6.0


The implementation of this new method takes advantage of the System.Runtime.CompilerServices.CallerArgumentExpressionAttribute attribute to simplify this further, by not requiring the developer to explicitly provide the name of the parameter that's being guarded.

The discussion that ended up introducing this new API can be found here: https://github.com/dotnet/runtime/issues/48573

The PR that introduced it in the .NET 6 code base can be found here: https://github.com/dotnet/runtime/pull/55594

yv989c
  • 1,453
  • 1
  • 14
  • 20
  • As of creation of the nullable context, all null checks should cease to exist. – AgentFire Oct 12 '21 at 20:21
  • @AgentFire I don't believe that's the case. The introduction of nullable contexts is a welcome addition that will avoid common bugs around this topic (particularly in new codebases) at build-time, but you can still get bitten by dereferences at run-time. You can read more about these pitfalls here: https://learn.microsoft.com/en-us/dotnet/csharp/nullable-references#known-pitfalls – yv989c Oct 14 '21 at 05:28
  • Yes, you can get bitten by old 3rd party libs, which are handled by nullable context just as they should be. Or better else you can get bitten by IGNORING or MISUSING the nullable context features. Which doesn't mean that you should start writing those "ThrowIfNull"s all over again. – AgentFire Oct 14 '21 at 11:12
4

I would do this way to avoid hardcoding parameter names. Tomorrow it can change, and you have more work then:

public static void ThrowIfNull<T>(this T item) where T : class
{
    var param = typeof(T).GetProperties()[0];
    if (param.GetValue(item, null) == null)
        throw new ArgumentNullException(param.Name);
}

And call it:

public void Proc(object parameter)
{
    new { parameter }.ThrowIfNull(); //you have to call it this way.

    // Main code.
}

The performance hit is trivial (on my mediocre computer it ran for 100000 times just under 25 ms), much faster than Expression based approach seen typically

ThrowIfNull(() => resource);

One such here. But surely don't use this if you cant afford that much hit..

You can also extend this for properties of objects.

new { myClass.MyProperty1 }.ThrowIfNull();

You can cache property values to improve performance further as property names don't change during runtime.

See this question additionally: Resolving a parameter name at runtime

nawfal
  • 70,104
  • 56
  • 326
  • 368
  • From your code sample, it returns if the object is null, are you sure it is working? – Vincent Nov 05 '14 at 01:33
  • I'm not sure what you mean here. Which object? The anonymous object? Yes it does return null from the function, which is a poor design choice imo. Better to throw there too. – nawfal Nov 05 '14 at 05:36
  • I think Vincent meant in the implementation of the "ThrowIfNull" method in the first code sample, in the first if statement it would return if the object was null and not throw an error. – Mayoweezy Mar 18 '16 at 10:40
0

What about using Expression Trees (from Visual Studio Magazine):

using System;
using System.Linq.Expressions;
namespace Validation
{
   public static class Validator
   {
     public static void ThrowIfNull(Expression<Func<object>> expression)
     {
       var body = expression.Body as MemberExpression;
       if( body == null)
       {
         throw new ArgumentException(
           "expected property or field expression.");
       }
       var compiled = expression.Compile();
       var value = compiled();
       if( value == null)
       {
         throw new ArgumentNullException(body.Member.Name);
       }
     }
     public static void ThrowIfNullOrEmpty(Expression<Func<String>> expression)  
     {
        var body = expression.Body as MemberExpression;
        if (body == null)
        {
          throw new ArgumentException(
            "expected property or field expression.");
        }
        var compiled = expression.Compile();
        var value = compiled();
        if (String.IsNullOrEmpty(value))
        {
          throw new ArgumentException(
            "String is null or empty", body.Member.Name);
        }
      }
   }

}

Used like this:

public void Proc(object parameter1, object parameter2, string string1)
{
    Validator.ThrowIfNull(() => parameter1);
    Validator.ThrowIfNull(() => parameter2);
    Validator.ThrowIfNullOrEmpty(() => string1);
    // Main code.
}
Steve Ford
  • 7,433
  • 19
  • 40
  • 1
    Too late for that. you can now use the `nameof()` operator for member names. And it is compile-time processed, unlike your solution. – AgentFire Feb 07 '17 at 11:19
  • @AgentFire you are missing the point of the solution. Here he doesnt have to pass in `parameter1` more than once. By passing the argument as an expression to the helper class, he gets both the value as well as the param name :) – nawfal Apr 24 '20 at 17:49
0

Based on C# 10, I use the ThrowIfNull extension method:

public static class CheckNullArgument
{
    public static T ThrowIfNull<T>(this T argument)
    {
        ArgumentNullException.ThrowIfNull(argument);

        return argument;
    }
}

Usage:

public class UsersController
{
    private readonly IUserService _userService;

    public UsersController(IUserService userService)
    {
        _userService = userService.ThrowIfNull();
    }
}
Mohsen Saniee
  • 204
  • 2
  • 17
-1

Second one seems more elegant way of handling the same. In this case you can put restriction on every managed object.

internal static void ThrowIfNull(this object o, string paramName)
{
       if (o == null)
        throw new ArgumentNullException(paramName);
}
Shailesh
  • 1,178
  • 11
  • 12