在调用base之前检查构造函数参数是否为null

时间:2011-01-26 10:18:39

标签: c#

我通常以下列方式检查构造函数参数的空值:

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,该怎么办?

有关如何解决此问题的任何建议?

5 个答案:

答案 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 operatornull-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");
              }

        }
    }