I would like to validate multiple parameters and throw an ArgumentNullException
if any of them are null
. For the sake of argument, let's assume I've got this:
public void DoSomething(SomeClass param1, SomeClass param2, SomeClass param3);
Of course, I could do:
if (param1 == null)
throw new ArgumentNullException(nameof(param1));
if (param2 == null)
throw new ArgumentNullException(nameof(param2));
if (param3 == null)
throw new ArgumentNullException(nameof(param3));
But it's not particularly pretty, especially if it's a recurring check in throughout the application. So, I thought I would do this:
public static class ValidationExtensions
{
public static void NullCheck<T>(this T subject)
{
if (T == null)
throw new ArgumentNullException();
}
}
// ...
param1.NullCheck();
param2.NullCheck();
param3.NullCheck();
But this way I lose the nameof
. I can't do nameof(subject)
as that's meaningless.
Of course, this is an option:
public static class ValidationExtensions
{
public static void NullCheck<T>(this T subject, string parameterName)
{
if (T == null)
throw new ArgumentNullException(parameterName);
}
}
// ...
param1.NullCheck(nameof(param1));
param2.NullCheck(nameof(param2));
param3.NullCheck(nameof(param3));
But it seems prone to error, with the repeated params... and, to be honest, just not pretty.
Is there a nice way of doing this? Ideally without using any external libraries.
The most succinct and maintainable solution would be what you have, or C#7 Throw Expression
param1 = param1 ?? throw new ArgumentNullException(nameof(param1));
You could use Expressions and some smarts, though i wouldn't recommend this, its smells and hides simple logic behind an abstraction and overhead. Additionally, it relies on unspecified behaviour that might change in the future
However, all that aside, i give you Expressions
public static class Validator
{
public static void Validate<T>(Expression<Func<string, T>> f)
{
var name = (f.Body as MemberExpression).Member.Name;
if(f.Compile().Invoke(name) == null)
throw new ArgumentNullException(name);
}
}
The reason this works, is because the compiler generates a class for the lambda expression (a closure) and the local variable becomes a property Member.Name
, which means it should also work for properties too (untested)
Usage
public static void Test(string param1, string param2)
{
Validator.Validate(x => param1);
}
public static void Main()
{
Test(null,"asdf");
}
Output
Value cannot be null. Parameter name: param1
Note : Truthfully i haven't thought about this too much or tested it more than a couple of use cases, it may or may not work, so i am not responsible for the people you injure with this code