Бросая АргументNullException - PullRequest
56 голосов
/ 15 декабря 2008

Предположим, у меня есть метод, который принимает какой-либо объект в качестве аргумента. Теперь скажите, что если этому методу передан пустой аргумент, это фатальная ошибка, и должно быть выдано исключение. Стоит ли мне кодировать что-то вроде этого (помните, что это тривиальный пример):

void someMethod(SomeClass x)
{
    if (x == null){
        throw new ArgumentNullException("someMethod received a null argument!");
    }

    x.doSomething();
}

Или для меня безопаснее просто полагаться на то, что оно вызывает NullException, когда он вызывает x.doSomething ()?

Во-вторых, предположим, что someMethod является конструктором, и x не будет использоваться, пока не будет вызван другой метод. Должен ли я немедленно сгенерировать исключение или подождать, пока x потребуется, и затем сгенерировать исключение?

Ответы [ 11 ]

59 голосов
/ 15 декабря 2008

Я предпочитаю ArgumentNullException, чем NullReferenceException, что не обеспечит проверка аргумента. В общем, я предпочитаю всегда проверять на недействительность, прежде чем пытаться вызвать метод для потенциально нулевого объекта.

Если метод является конструктором, то он будет зависеть от нескольких факторов: есть ли открытый установщик свойства и насколько вероятно, что объект будет фактически использован. Если есть общедоступный установщик, то недопустимое предоставление допустимого экземпляра через конструктор будет разумным и не должно приводить к исключению.

Если общедоступного сеттера нет, и можно использовать содержащий объект без ссылки на внедренный объект, вы можете отложить проверку / исключение до попытки его использования. Тем не менее, я думаю, что общий случай заключается в том, что внедренный объект необходим для функционирования экземпляра, и поэтому исключение ArgumentNull совершенно разумно, поскольку экземпляр не может функционировать без него.

31 голосов
/ 15 декабря 2008

Я всегда следую практике быстро проваливаюсь . Если ваш метод зависит от X и вы понимаете, что X может быть передан в ноль, проверьте его на ноль и немедленно вызовите исключение вместо продления точки отказа.

2016 обновление:

Пример из реального мира. Я настоятельно рекомендую использовать Jetbrains Annotations .

[Pure]
public static object Call([NotNull] Type declaringType, 
                          [NotNull] string methodName, 
                          [CanBeNull] object instance)
{
    if (declaringType == null) throw new ArgumentNullException(nameof(declaringType));
    if (methodName == null) throw new ArgumentNullException(nameof(methodName));

Защитные операторы были значительно улучшены с C # 6, обеспечивающим оператор nameof.

14 голосов
/ 15 декабря 2008

Я предпочитаю явное исключение по следующим причинам:

  • Если метод имеет более одного аргумента SomeClass, он дает вам возможность сказать, какой он есть (все остальное доступно в стеке вызовов).
  • Что делать, если вы делаете что-то, что может иметь побочный эффект, прежде чем ссылаться на x?
10 голосов
/ 15 декабря 2008

Я согласен с идеей быстрого провала - однако разумно знать, почему неудачный пост практичен. Рассмотрим этот пример:

void someMethod(SomeClass x)
{       
    x.Property.doSomething();
}

Если вы полагаетесь на NullReferenceException, чтобы сообщить вам, что что-то не так, как вы узнаете, что было нулевым? Трассировка стека даст вам только номер строки, а не ссылку на ноль. В этом примере x или x.Property могли бы быть как нулевыми, так и без быстрого быстрого провала с предварительной проверкой, вы не будете знать, что это.

9 голосов
/ 15 декабря 2008

Я бы тоже предпочел проверку параметров с явным ArgumentNullException.

Просмотр метаданных:

 //
    // Summary:
    //     Initializes a new instance of the System.ArgumentNullException class with
    //     the name of the parameter that causes this exception.
    //
    // Parameters:
    //   paramName:
    //     The name of the parameter that caused the exception.
    public ArgumentNullException(string paramName);

Вы можете видеть, что строка должна быть именем параметра, то есть нулем, и поэтому дать разработчику подсказку о том, что идет не так.

5 голосов
/ 15 декабря 2008

Вам следует явно выдать ArgumentNullException, если вы ожидаете, что входные данные не будут нулевыми. Возможно, вы захотите написать класс с именем Guard, который предоставляет вспомогательные методы для этого. Итак, ваш код будет:

void someMethod(SomeClass x, SomeClass y)
{
    Guard.NotNull(x,"x","someMethod received a null x argument!");
    Guard.NotNull(y,"y","someMethod received a null y argument!");


    x.doSomething();
    y.doSomething();
}

Метод NonNull будет выполнять проверку на пустоту и генерировать исключение NullArgumentException с сообщением об ошибке, указанным в вызове.

5 голосов
/ 15 декабря 2008

Лучше бросить ArgumentNullException раньше, чем позже. Если вы его выбросите, вы можете предоставить более полезную информацию о проблеме, чем NullReferenceException.

4 голосов
/ 15 декабря 2008

1- Делайте это явно, если вам не нужно значение Null. В противном случае, когда кто-то еще будет смотреть ваш код, он будет думать, что принятие значения Null принято.

2- Делайте это как можно быстрее. Таким образом, вы не пропагандируете «неправильное» поведение наличия Null, когда это не предполагается.

3 голосов
/ 15 декабря 2008

Если вы программируете в обороне, вы должны быстро потерпеть неудачу. Так что проверьте свои входные данные и ошибки в начале вашего кода. Вы должны быть добры к своим абонентам и дать им самое наглядное сообщение об ошибке, какое только можете.

0 голосов
/ 19 июля 2017

Вы можете использовать синтаксис, подобный следующему, чтобы не просто выбросить ArgumentNullException, но и присвоить этому исключению имя параметра как часть его текста ошибки. Например,.

void SomeMethod(SomeObject someObject)
{
    Throw.IfArgNull(() => someObject);
    //... do more stuff
}

Класс, используемый для возбуждения исключения:

public static class Throw
{
    public static void IfArgNull<T>(Expression<Func<T>> arg)
    {
        if (arg == null)
        {
            throw new ArgumentNullException(nameof(arg), "There is no expression with which to test the object's value.");
        }

        // get the variable name of the argument
        MemberExpression metaData = arg.Body as MemberExpression;
        if (metaData == null)
        {
            throw new ArgumentException("Unable to retrieve the name of the object being tested.", nameof(arg));
        }

        // can the data type be null at all
        string argName = metaData.Member.Name;
        Type type = typeof(T);
        if (type.IsValueType && Nullable.GetUnderlyingType(type) == null)
        {
            throw new ArgumentException("The expression does not specify a nullible type.", argName);
        }

        // get the value and check for null
        if (arg.Compile()() == null)
        {
            throw new ArgumentNullException(argName);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...