我通常以下列方式检查构造函数参数的空值:
public class SomeClass(SomeArgument someArgument)
{
if(someArgument == null) throw new ArgumentNullException("someArgument");
}
但是说我有一个继承自另一个类的类:
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)
{
}
}
现在有人构建了TheInheritor
这样的实例:
var theVar = new TheInheritor(null);
我无法想到在调用null
之前检查base
的方法(并抛出NullReferenceException
)。如果让TheBase
的构造函数接受TheArgument
的实例,我就看不出如何进行这种理智检查。但是,如果TheArgument
仅与TheInheritor
相关,并且还有很多其他类继承自TheBase
,该怎么办?
有关如何解决此问题的任何建议?
答案 0 :(得分:42)
你可以这样做:
public TheInheritor(TheArgument theArgument)
: base(ConvertToId(theArgument))
{
}
private static int ConvertToId(TheArgument theArgument)
{
if (theArgument == null)
{
throw new ArgumentNullException("theArgument");
}
return theArgument.Id;
}
或更一般地说,这样的事情:
public TheInheritor(TheArgument theArgument)
: base(Preconditions.CheckNotNull(theArgument).Id)
{
}
其中Preconditions
是其他地方的实用程序类,如下所示:
public static class Preconditions
{
public static T CheckNotNull<T>(T value) where T : class
{
if (value == null)
{
throw new ArgumentNullException();
}
return value;
}
}
(当然,这会丢失参数名称,但如果需要,您也可以将其传递出去。)
答案 1 :(得分:1)
作为替代方案,您可以使用Func&lt;&gt;用于ID选择:
public class TheInheritor : TheBase
{
public TheInheritor(TheArgument theArgument, Func<TheArgument, int> idSelector)
: base(idSelector(theArgument))
{
...
}
}
甚至
public class TheInheritor<T> : TheBase where T : TheArgument
{
public TheInheritor(T theArgument, Func<T, int> idSelector)
: base(idSelector(theArgument))
{
...
}
}
异常将自行落实,并且您将强制被调用者决定如何指定对象的Id
。
答案 2 :(得分:1)
从C#6.0起,您可以将null-coalescing operator与null-conditional operator结合使用,如下所示:
public TheInheritor(TheArgument theArgument)
: base(theArgument?.TheId ?? throw new ArgumentNullException(nameof(theArgument)))
{
}
答案 3 :(得分:0)
作为一般规则,我只会担心我在课堂上使用的参数。我只会直接通过基类使用的参数,让该类担心它。
答案 4 :(得分:0)
你可以像这样调用基础构造函数(为了参数,假设-1表示无效值):
public class TheInheritor : TheBase
{
public TheInheritor(TheArgument theArgument) : base(theArgument == null ? -1 : theArgument.TheId)
{
if (theArgument == null)
{
throw new ArgumentNullException("theArgument");
}
}
}