Checking constructor parameter for null before calling base
I usually check constructor arguments for null values in the following manner:
public clas开发者_JAVA技巧s SomeClass(SomeArgument someArgument)
{
if(someArgument == null) throw new ArgumentNullException("someArgument");
}
But say I have a class that inherits from another class:
public abstract class TheBase
{
public TheBase(int id)
{
}
}
public class TheArgument
{
public int TheId { get; set; }
}
public class TheInheritor : TheBase
{
public TheInheritor(TheArgument theArgument) : base(theArgument.TheId)
{
}
}
And someone now constructs an instance of TheInheritor
like this:
var theVar = new TheInheritor(null);
I can't think of a way that to check for null
before base
is being called (and throwing a NullReferenceException
). Short of letting TheBase
's constructor accept an instance of TheArgument
I can't see how I could have this sanity-check. But what if TheArgument
is related only to TheInheritor
and there are a lot of other classes inheriting from TheBase
?
Any recommendations on how to solve this?
You can do it with something like this:
public TheInheritor(TheArgument theArgument)
: base(ConvertToId(theArgument))
{
}
private static int ConvertToId(TheArgument theArgument)
{
if (theArgument == null)
{
throw new ArgumentNullException("theArgument");
}
return theArgument.Id;
}
Or more generally, something like this:
public TheInheritor(TheArgument theArgument)
: base(Preconditions.CheckNotNull(theArgument).Id)
{
}
where Preconditions
is a utility class elsewhere, like this:
public static class Preconditions
{
public static T CheckNotNull<T>(T value) where T : class
{
if (value == null)
{
throw new ArgumentNullException();
}
return value;
}
}
(This loses the argument name, of course, but you could pass that in as well if necessary.)
As of C# 6.0 you can use null-coalescing operator combined with the null-conditional operator like this:
public TheInheritor(TheArgument theArgument)
: base(theArgument?.TheId ?? throw new ArgumentNullException(nameof(theArgument)))
{
}
As an alternative, you could use a Func<> for id selection:
public class TheInheritor : TheBase
{
public TheInheritor(TheArgument theArgument, Func<TheArgument, int> idSelector)
: base(idSelector(theArgument))
{
...
}
}
or even
public class TheInheritor<T> : TheBase where T : TheArgument
{
public TheInheritor(T theArgument, Func<T, int> idSelector)
: base(idSelector(theArgument))
{
...
}
}
The exceptions will fall on their own, as well as you will force the callee to decide how to specify the object's Id
.
As a general rule I would only worry about the parameters I am using in my class. Parameters that are only used by the base class I would just pass straight through and let that class worry about it.
You could call the base constructor like this (for the sake of argument assuming -1 indicates an invalid value):
public class TheInheritor : TheBase
{
public TheInheritor(TheArgument theArgument) : base(theArgument == null ? -1 : theArgument.TheId)
{
if (theArgument == null)
{
throw new ArgumentNullException("theArgument");
}
}
}
精彩评论