Подтвердить что ты не робот

Проверка параметра конструктора для null перед вызовом базы

Я обычно проверяю аргументы конструктора для нулевых значений следующим образом:

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?

Любые рекомендации о том, как решить эту проблему?

4b9b3361

Ответ 1

Вы можете сделать это примерно так:

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;
    }
}

(Это, конечно, теряет имя аргумента, но вы также можете передать это в случае необходимости.)

Ответ 2

В качестве альтернативы вы можете использовать выбор Func < > for 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.

Ответ 3

Как правило, я буду беспокоиться только о параметрах, которые я использую в своем классе. Параметры, которые используются базовым классом I, просто пройдут прямо, и пусть этот класс беспокоится об этом.

Ответ 4

Вы можете вызвать базовый конструктор, как это (ради аргумента, принимающего -1, указывает недопустимое значение):

    public class TheInheritor : TheBase
    {
        public TheInheritor(TheArgument theArgument) : base(theArgument == null ? -1 : theArgument.TheId)
        {
              if (theArgument == null)
              {
                  throw new ArgumentNullException("theArgument");
              }

        }
    }