'ArgumentNullException - how to simplify?
I've noticed this code crops up a lot in my constructors:
if (someParam == null) throw new ArgumentNullException("someParam");
if (someOtherParam == null) throw new ArgumentNullException("someOtherParam");
...
I have a few constructors where several things are injected and must all be non-null. Can anyone think of a way to streamline this? The only thing I can think of is the following:
public static class ExceptionHelpers
{
public static void CheckAndThrowArgNullEx(IEnumerable<KeyValuePair<string, object>> parameters)
{
foreach(var parameter in parameters)
if(parameter.Value == null) throw new ArgumentNullException(parameter.Key);
}
}
However, the usage of that would be something like:
ExceptionHelper.CheckAndThrowArgNullEx(new [] {
new KeyValuePair<string, object>("someParam", someParam),
new KeyValuePair<string, object>("someOtherParam", someOtherParam),
... });
... which doesn't really help streamline the code. Tuple.Create() instead of KVPs doesn't work because Tuple's GTPs aren't covariant (even though IEnumerable's GTP is). Any ideas?
Solution 1:[1]
Update for C# 7
You can use a throw expression with the null coalescing operator. Here is an example from that page:
public string Name
{
get => name;
set => name = value ??
throw new ArgumentNullException(paramName: nameof(value), message: "New name must not be null");
}
Original Answer
Personally, I use the ThrowIfNull extension method. I don't know who to credit but I definitely didn't invent it. It's nice because you can do assignment with the return value:
public static T ThrowIfNull<T>(this T argument, string argumentName)
{
if (argument == null)
{
throw new ArgumentNullException(argumentName);
}
return argument;
}
Usage:
this.something = theArgument.ThrowIfNull("theArgument");
// or in C# 6
this.something = theArgument.ThrowIfNull(nameof(theArgument));
(Although some people think it's weird to call an extension method on a null instance)
If you really want to check more than one argument at a time, your example might be more streamlined if you used a params signature like so:
public static void CheckAndThrowArgNullEx(params object[] argsAndNames)
{
for (int i = 0; i < argsAndNames.Length; i += 2)
{
if (argsAndNames[i] == null)
{
string argName = (string)argsAndNames[i + 1];
throw new ArgumentNullException(argName);
}
}
}
and the usage would be:
CheckAndThrowArgNullEx(arg1, "arg1", arg2, "arg2");
// or in C# 6
CheckAndThrowArgNullEx(arg1, nameof(arg1), arg2, nameof(arg2));
On second thought, as KeithS mentions in the comments, it would probably be better to implement this as a set of overloads rather than using params object[] like this:
static void Check(object arg1, string arg1Name) { ... }
static void Check(object arg1, string arg1Name, object arg2, string arg2Name) { ... }
// and so on...
Solution 2:[2]
Try this: One line.
accounts = accounts ?? throw new ArgumentNullException(nameof(accounts));
Also, use nameof(), if the variable is ever renamed you will not have to hunt down all the "variable"s, let nameof() do that.
Solution 3:[3]
.NET 6 and beyond
There is a new method in .NET API ArgumentNullException.ThrowIfNull(someParameter).
This method is probably the best option which you can get.
C# 11 (currently as proposal)
Use new Bang Bang operator !! on a parameter to implicit check for null.
public string SomeFunction(Foo foo!!)
{
// here, foo is already checked for null
// ArgumentNullException(nameof(foo)) is thrown when foo = null
return $"Here is {foo.Bar}";
}
TL;DR
The compiler will emit this code for every !! use
if (someArgument is null)
{
throw new ArgumentNullException(nameof(someArgument));
}
Our SomeFunction will be transformed into
public string SomeFunction(Foo foo!!)
{
if (foo is null)
{
throw new ArgumentNullException(nameof(foo));
}
return $"Here is {foo.Bar}";
}
Solution 4:[4]
There are several way to go about this.
Option A:
Break your functions into two - validation and implementation (you can see examples of this in Jon Skeet's EduLinq).
Option B:
Use code contracts that expect the parameters to be non-null.
Option C:
Using aspect oriented technologies such as code weaving to extract these checks out into an aspect. (as J Torres answered).
Option D:
Use Spec#, as CodeInChaos commented.
Option E:
???
Solution 5:[5]
In c# 10 you can just do this:
ArgumentNullException.ThrowIfNull(z);
And you will got this error:
System.ArgumentNullException: Value cannot be null. (Parameter 'z')
at System.ArgumentNullException.Throw(String paramName)
at System.ArgumentNullException.ThrowIfNull(Object argument, String paramName)
at ConsoleApp1.SomeClass.Join(String a, String b)
Under the hood, it use the new CallerArgumentExpression attribure.
Solution 6:[6]
public class TestClass
{
public TestClass()
{
this.ThrowIfNull(t=>t.Str, t=>t.Test);
//OR
//this.ThrowIfNull(t => t.X)
// .ThrowIfNull(t => t.Test);
}
string Str = "";
public TestClass Test {set;get;}
}
public static class SOExtension
{
public static T ThrowIfNull<T>(this T target, params Expression<Func<T, object>>[] exprs)
{
foreach (var e in exprs)
{
var exp = e.Body as MemberExpression;
if (exp == null)
{
throw new ArgumentException("Argument 'expr' must be of the form x=>x.variableName");
}
var name = exp.Member.Name;
if (e.Compile()(target) == null)
throw new ArgumentNullException(name,"Parameter [" + name + "] can not be null");
}
return target;
}
}
Solution 7:[7]
In c# 7 can be done like this:
_ = someParam ?? throw new ArgumentNullException(nameof(someParam));
After release optimisation you will get:
if (someParam == null)
throw new ArgumentNullException(nameof(someParam));
Solution 8:[8]
If you aren't opposed to third party utilities, PostSharp provides clean ways to inject such validations. This blog post provides a solution to your problem.
Update: See new Validating-parameters features in PostSharp 3
Solution 9:[9]
How about an extension method?
public static void ThrowExceptionIfNull(this object argument, string argumentName)
{
if(argument == null)
throw new ArgumentNullException(argumentName);
}
Then your code at least reads a little more fluently:
someParam.ThrowExceptionIfNull("someParam");
Otherwise, I would agree with the others to split the functionality or use AOP (ie. PostSharp)
Solution 10:[10]
Well, the boilerplate is hard to avoid. You could switch to using the Bertrand Meyers' Eiffel programming language and EiffelStudio instead of C# and Visual Studio and start practicing "design by contract™".
Eiffel is fully CLR-compliant these days.
Solution 11:[11]
There are a lot of valid solutions already, but here's my take:
using System.Diagnostics;
using System.Reflection;
public SomeConstructor(int? par1, int? par2, string par3)
{
CheckThrowNull(par1, par2, par3);
//rest of constructor code...
}
///<param name="values"> Values must be given in order </param>
public static void CheckThrowNull(params object[] values)
{
StackTrace stackTrace = new StackTrace();
ParameterInfo[] parameters = stackTrace.GetFrame(1).GetMethod().GetParameters(); //get calling method's parameters (or constructor)
if (parameters.Length != values.Length)
{
throw new ArgumentException("Incorrect number of values passed in");
}
for (int i = 0; i < parameters.Length; i++)
{
if (values[i] == null)
{
//value was null, throw exception with corresponding parameter name
throw new ArgumentNullException(parameters[i].Name);
}
}
}
The general idea is that two parallel arrays are established, one of type ParameterInfo, and one containing the values of the parameter. The latter has to passed in because parameter values aren't easily (and I think impossible) obtainable via reflection. To give credit where it is due, I found how to get the calling method here: http://www.csharp-examples.net/reflection-calling-method-name/
Personally, I don't like using System.Diagnosics except for debugging, so I would make a slight modification, having calling code be:
CheckThrowNull(MethodBase.GetCurrentMethod(), par1, par2, par3);
and the method being
CheckThrowNull(MethodBase method, params object[] values)
{
ParameterInfo[] parameters = method.GetParameters();
//rest of code same
}
The down-side is its a little non-extensible and can't easily be made to check if just some of the arguments are null.
Solution 12:[12]
I wrote benchmark application with multiple variations of extracting argument name (via anonymous class + reflection / MemberExpression / Func / etc)
Github link to benchmark sources: https://github.com/iXab3r/NullCheckCompetition
I got results, that are showing, that the fastest method is through use of anonymous class.
.NET 40 / X64
Fail (i.e. argument IS null and name extraction method is executed)
- FailAnonymousClass 67.87 ns
- FailDoubleLambda 643.98 ns
- FailLazyAnonymousClass 69.36 ns
- FailRawCheck 1.08 ns
- FailSingleLambda 643.27 ns
Success (i.e. argument is not null)
- SuccessAnonymousClass 6.33 ns
- SuccessDoubleLambda 8.48 ns
- SuccessLazyAnonymousClass 8.78 ns
- SuccessRawCheck 1.08 ns
- SuccessSingleLambda 628.28 ns
Solution 13:[13]
I think most of the above are ok but none of them are really an improvement to what you already have so I would just go for the KIS, Keep It Simple, and that is what you started with.
It's clean, extremly readable and its fast. The only thing it's a bit long
Solution 14:[14]
Update for C# 10 (.NET >= 6):
_person = person.ThrowIfNull();
public static T ThrowIfNull<T>(this T? argument, string? message = default, [CallerArgumentExpression("argument")] string? paramName = default)
{
return argument ?? throw new ArgumentNullException(paramName, message);
}
Solution 15:[15]
With C# 11 and .NET 6.0 you can do this:
public bool DoSomething(string name)
{
ArgumentNullException.ThrowIfNull(name);
// Do your stuff, name is not null
}
Solution 16:[16]
It is actually possible to retrieve the argument name from the lambda expression without going through the Expression type. This is how it can be done:
static void SampleMethod(string arg1)
{
ThrowIfNull(() => arg1);
// continue to other normal stuff here...
}
public static void ThrowIfNull<T>(Func<T> lambda)
where T : class
{
if (lambda() == null)
{
throw new ArgumentNullException(lambda.Target.GetType().GetFields()[0].Name);
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
