简体   繁体   中英

Checking constructor parameter for null before calling base

I usually check constructor arguments for null values in the following manner:

public class 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 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 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 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");
              }

        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM