What is the best practice in case one argument is null?
And for the C# 3.0 developers amongst us a great way to encapsulate this null checking is inside an extension method.
public void Foo(string arg1, int? arg2)
{
arg1.ThrowOnNull();
arg2.ThrowOnNull();
}
public static class extensions
{
public static void ThrowOnNull<T>(this T argument) where T : class
{
if(argument == null) throw new ArgumentNullException();
}
}
And if you wanted you could always overload that to take an argument name.
An approach which I use and I may have picked up from the NHibernate source is to create a static class Guard
, used as follows:
public void Foo(object arg1, string arg2, int arg3)
{
Guard.ArgumentNotNull(arg1, "arg1");
Guard.ArgumentNotNullOrEmpty(arg2, "arg2");
Guard.ArgumentGreaterThan(arg3, "arg3", 0);
//etc.
}
public static class Guard
{
public static void ArgumentNotNull(object argument, string parameterName)
{
if (parameterName == null)
throw new ArgumentNullException("parameterName");
if (argument == null)
throw new ArgumentNullException(parameterName);
}
//etc.
}
This cuts down a lot of the chaff at the beginning of methods and it performs well.
You should think about the method, what it needs to do and with what data. If null values represent actual failure conditions, use exceptions. If null values are acceptable, accept them.
Think about the principles from design by contract, specifically what the preconditions to your function are, and standardize a way to enforce them (which Matt and Lou both suggest in their answers so I don't need to go into detail).
Another important thing to consider is the size of your method signatures. If you have a lot of parameters for your methods, this probably means you have bad abstractions. You can cut down on the number of parameter checks you have to make if you group parameters together in collection objects and use those objects as parameters. You can move the parameter checking to those objects instead of having to check them in every function that uses them.
So instead of passing ten related parameters to every function, figure out the few that are used in every function and package them up in an object, and include in that object methods to validate the parameters. This has the added advantage of being easy to change should the rules regarding one parameter need to be updated.
Make an ArgChecker class with something like this
ArgChecker.ThrowOnStringNullOrEmpty(userName, "Username");
where ThrowOnStringNullOrEmpty is
public static void ThrowOnStringNullOrEmpty(string arg, string name)
{
if (string.IsNullOrEmpty(arg))
throw new ArgumentNullException(name + " can't be null");
}
You could also try to process a list of arguments using a params arg, like:
public static void ThrowOnAnyStringNullOrEmpty(params string[] argAndNames)
{
for (int i = 0; i < argAndName.Length; i+=2) {
ThrowOnStringNullOrEmpty(argAndNames[i], argAndNames[i+1]);
}
}
and call like this
ArgChecker.ThrowOnAnyStringNullOrEmpty(userName, "Username", Email, "email");