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

ArgumentException или ArgumentNullException для строковых параметров?

В лучшем случае лучше, чем лучше:

public void SomeMethod(string str) 
{
    if(string.IsNullOrEmpty(str))
    {
        throw new ArgumentException("str cannot be null or empty.");
    }

    // do other stuff
}

или

public void SomeMethod(string str) 
{
    if(str == null) 
    {
        throw new ArgumentNullException("str");
    }

    if(str == string.Empty)
    {
        throw new ArgumentException("str cannot be empty.");
    }

    // do other stuff
}

Вторая версия кажется более точной, но также более громоздкой, чем первая. Я обычно иду с №1, но решил, что я проверил бы, есть ли аргумент для №2.

4b9b3361

Ответ 1

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

str.ThrowIfNullOrEmpty("str");


public static void ThrowIfNullOrEmpty(this string value, string name)
{
    if (value == null)
    {
        throw new ArgumentNullException(name);
    }
    if (value == "")
    {
        throw new ArgumentException("Argument must not be the empty string.",
                                    name);
    }
}

Другая потенциально полезная форма - это та, которая возвращает исходную строку, если все в порядке. Вы могли бы написать что-то вроде этого:

public Person(string name)
{
    this.name = name.CheckNotEmpty();
}

Другой вариант, который следует рассмотреть, заключается в использовании Code Contracts в качестве альтернативы выбросу собственных исключений.

Ответ 2

Я бы предложил использовать первый. Если ваш метод не ожидает нулевой или пустой строки, то действительно не имеет значения, было ли передано значение null или empty - важно сообщить об ошибке и это то, что делает 1-й вариант.

Ответ 3

Другая возможность - исключение ArgumentOutOfRange:

Исключение, которое вызывается, когда значение аргумента выходит за допустимый диапазон значений, определяемый вызываемым методом.

Ответ 4

Бросок пустой ссылки на пустую строку может привести к путанице - значение по умолчанию для строки равно нулю и будет указывать на неинициализированную строку, тогда как пустая строка может представлять другие проблемы.

Мне нравится идея Jon Skeet, однако мне нравится явно использовать throw, а не иметь отдельную функцию.

Вместо этого вы можете бросить следующий класс:

 public class ArgumentNullOrEmptyException : ArgumentNullException
{
    #region Properties And Fields

    private static string DefaultMessage => $"A value cannot be null or empty{Environment.NewLine}";

    #endregion

    #region Construction and Destruction

    public ArgumentNullOrEmptyException()
        : base(DefaultMessage)
    {
    }

    public ArgumentNullOrEmptyException(string paramName)
        : base(paramName, 
                  $"{DefaultMessage}" +
                  $"Parameter name: {paramName}")
    {
    }

    public ArgumentNullOrEmptyException(string message, Exception innerException)
        : base($"{DefaultMessage}{message}", innerException)
    {
    }

    public ArgumentNullOrEmptyException(string paramName, string message)
        : base(paramName, 
              $"{DefaultMessage}" +
              $"Parameter name: {paramName}{Environment.NewLine}" +
              $"{message}")
    {
    }

    #endregion

    public static void ThrowOnNullOrEmpty(string paramName, string paramValue)
    {
        if(string.IsNullOrEmpty(paramValue))
            throw new ArgumentNullOrEmptyException(paramName);
    }
    public static void ThrowOnNullOrEmpty(string paramValue)
    {
        if (string.IsNullOrEmpty(paramValue))
            throw new ArgumentNullOrEmptyException();
    }


    public static void ThrowOnNullOrEmpty(string paramName, object paramValue)
    {
        //ThrowOnNullOrEmpty another object that could be 'empty' 

        throw new NotImplementedException();
    }
}



        private static void AFunctionWithAstringParameter(string inputString)
    {
        if(string.IsNullOrEmpty(inputString)) throw new ArgumentNullOrEmptyException(nameof(inputString));

        //Or ..
        ArgumentNullOrEmptyException.ThrowOnNullOrEmpty(nameof(inputString), inputString);
    }

Обратите внимание, что мой производный тип вызывает только базовый класс исключений, а не переопределяет свойство сообщения. Это связано с тем, что в "дополнительной информации" отладчика Visual Studio указано внутреннее сообщение, а не переопределенный тип. Это означает, что это единственный способ красиво отобразить сообщение во время отладки.