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

В моем приложении мне нужно создать исключение, если свойство определенного класса равно null или пустое (в случае, если оно является строкой). Я не уверен, что является лучшим исключением для использования в этом случае. Мне бы очень хотелось создать новое исключение, и я не уверен, что ArgumentNullException подходит в этом случае.

Должен ли я создать новое исключение или исключение, которое я могу использовать?

Я не против бросать исключение Application.

Ответ 1

Руководства MSDN для стандартных исключений:

Использовать значение для имени параметра неявного значения свойства сеттеры.

В следующем примере кода показан свойство, которое генерирует исключение, если вызывающий объект передает нулевой аргумент.

public IPAddress Address
{
    get
    {
        return address;
    }
    set
    {
        if(value == null)
        {
            throw new ArgumentNullException("value");
        }
        address = value;
    }
}

Кроме того, Руководства MSDN для дизайна свойств говорят:

Избегайте бросать исключения из свойство getters.

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

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

Итак, бросьте ArgumentNullException в сеттер на null и ArgumentException на пустой строке и ничего не сделайте в получателе. Поскольку сеттер выбрасывает и только у вас есть доступ к полю резервного копирования, легко убедиться, что он не будет содержать недопустимое значение. Наличие геттер-броска тогда бессмысленно. Это может быть хорошим местом для использования Debug.Assert.

Если вы действительно не можете предоставить соответствующий по умолчанию, то, полагаю, у вас есть три варианта:

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

  • Заменить свойство методами: метод setter, который генерирует при передаче недопустимого значения, и метод getter, который выдает InvalidOperationException, когда свойство никогда не было присвоено действительное значение.

  • Бросьте InvalidOperationException из получателя, так как вы можете считать, что свойство никогда не было назначено недопустимым. Хотя вы, как правило, не должны бросать из геттеров, я полагаю, это может быть хорошей причиной для исключения.

Если вы выберете варианты 2 или 3, вы также должны включить метод TryGet, который возвращает bool, который указывает, было ли свойство установлено на допустимое значение, и если это так возвращает это значение в параметре out, В противном случае вы вынуждаете вызывающих абонентов быть готовыми к обработке InvalidOperationException, если только они ранее не установили свойство самостоятельно и, следовательно, знали, что он не выбрасывает. Сравните int.Parse и int.TryParse.

Я бы предложил использовать вариант 2 с помощью метода TryGet. Он не нарушает никаких рекомендаций и предъявляет минимальные требования к вызывающему коду.


О других предложениях
ApplicationException является слишком общим. ArgumentException является слишком общим для null, но в остальном это не так. Документы MSDN снова:

Выбрасывать наиболее специфическое (наиболее производное) исключение, которое подходящее. Например, если метод получает нуль (Nothing in Visual Основной) аргумент, он должен бросить Вместо System.rgumentNullException его базового типа System.ArgumentException.

На самом деле вам не следует использовать ApplicationException вообще (docs):

Вывод пользовательских исключений из класса T: System.Exception, а не класса T: System.ApplicationException.

Первоначально предполагалось, что пользовательские исключения должны выводиться из класса ApplicationException; однако, как было установлено, это не означает значительную ценность. Дополнительные сведения см. В разделе "Рекомендации по устранению исключений".

InvalidOperationException предназначен не для тех случаев, когда аргументы метода или свойства недействительны, но если операция в целом недействительна ( "Документы" ). Его нельзя выбрасывать из сеттера:

Выбрасывать исключение System.InvalidOperationException, если оно находится в неудовлетворительном состоянии. System.InvalidOperationException должно быть выбрано, если набор свойств или вызов метода не подходят, учитывая текущее состояние объекта. Например, запись в System.IO.FileStream, который был открыт для чтения, должен генерировать исключение System.InvalidOperationException.

Кстати, InvalidOperationException означает, что операция недействительна для текущего состояния объекта. Если операция всегда недействительна для всего класса, вы должны использовать NotSupportedException.

Ответ 2

Я бы выбрал InvalidOperationException. MSDN говорит, что он "бросается, когда вызов метода недействителен для текущего состояния объекта".

Ответ 3

Ну, это не аргумент, если вы ссылаетесь на свойство класса. Таким образом, вы не должны использовать ArgumentException или ArgumentNullException.

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

Таким образом, использование ApplicationExeption или InvalidOperationException, вероятно, будет вашим лучшим выбором, убедившись, что для описания ошибки будет содержаться значимая строка.

Ответ 4

Пригодится ArgumentNullException, если кто-то пытается присвоить null.

Свойство никогда не должно бросаться на операцию чтения.

Ответ 5

Создает ли конструктор его значение, отличное от нуля? Если это так, я просто выброшу ArgumentNullException из сеттера.

Ответ 6

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

Подробное сообщение для конструктора было бы очень уместно здесь

Ответ 7

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

Кроме того, необходимо, чтобы свойство было установлено в конструкторе.

Таким образом вы вынуждаете действительное значение, а не возвращаетесь позже, и заявляете, что вы не можете определить баланс аккаунта, поскольку учетная запись не установлена.

Но я бы согласился с ответом bduke.

Ответ 8

Существует прецедент для растягивания интерпретации ArgumentNullException на значение "string argument is null или empty": System.Windows.Clipboard.SetText генерирует в этом случае ArgumentNullException.

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

Ответ 9

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