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

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

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

Я не против выбросить ApplicationException.


person Vadim    schedule 28.09.2009    source источник
comment
Имейте в виду, что свойства - это синтаксические подслащенные методы.   -  person Dykam    schedule 28.09.2009
comment
Связанное с этим интересное обсуждение: stackoverflow.com/questions / 1488472 /   -  person Joren    schedule 28.09.2009


Ответы (9)


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

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

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

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

Кроме того, в рекомендациях MSDN по проектированию собственности говорится :

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

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

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

Так что бросьте ArgumentNullException в сеттер на null и ArgumentException на пустую строку и ничего не делайте в геттере. Поскольку сеттер выбрасывает, и только у вас есть доступ к резервному полю, легко убедиться, что оно не будет содержать недопустимое значение. Бросок геттера тогда бессмыслен. Однако это может быть хорошим местом для использования _5 _.

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

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

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

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

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

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


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

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

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

Создавайте настраиваемые исключения из класса T: System.Exception, а не из класса T: System.ApplicationException.

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

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

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

Между прочим, InvalidOperationException используется, когда операция недопустима для текущего состояния объекта. Если операция всегда недопустима для всего класса, следует использовать _ 19_.

person Joren    schedule 28.09.2009
comment
@Joren, @Vadim указывает, что ему нужен инструктор по умолчанию, и у него нет разумного значения по умолчанию для этого поля, поэтому простого наблюдения за установщиком будет недостаточно для его сценария. - person bdukes; 28.09.2009
comment
Я согласен со всем, что здесь сказано. Я просто хочу добавить около ApplicationException, который хорошо использовать, если вы используете его для одной широкой цели, как и любые исключения состояния бизнес-программного обеспечения. Дело не в том, что система не может этого сделать, дело в том, что не будет. Было бы ужасно, если бы вы бросили ApplicationException за все, но я бы предпочел просто использовать AE, чем наследовать от него. Наследование на простое переименование чего-либо - напрасная трата усилий. - person Chris Marisic; 08.04.2014

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

person bdukes    schedule 28.09.2009
comment
Я не думаю, что это подходит для этого сценария. InvalidOperationException следует использовать только в том случае, если вызываемый объект недействителен. В этом случае вызываемый объект действителен на 100%, это недопустимый аргумент метода. - person JaredPar; 28.09.2009
comment
Вы бы выбросили InvalidOperationException, если бы объект находился в таком состоянии, что было бы недопустимо вообще использовать установщик свойств. То есть сама операция операция недействительна. В документах MSDN приводится пример записи в System.IO.FileStream, открытый для чтения. - person Joren; 28.09.2009
comment
Я полагаю, мы не знаем точного сценария того, что называется. Я работаю в предположении, что мы вызываем метод класса и пытаемся использовать свойство этого класса в методе. В этом случае объект недействителен для вызываемого метода (поскольку свойство необходимо установить до того, как метод может быть вызван). Похоже, @JaredPar рассматривает сценарий, в котором свойство аргумента не инициализируется. В таком случае его предложение ArgumentException имеет наибольший смысл. - person bdukes; 28.09.2009
comment
Я должен добавить, что мой предыдущий комментарий касался исключительно средства задания свойств. Свойство, которому не присвоено допустимое значение, действительно является примером недопустимого состояния. Я не думаю, что вам следует генерировать это исключение из средства получения свойства ... есть и другие варианты. - person Joren; 28.09.2009
comment
Если состояние инкапсулирующего объекта становится недействительным / нефункциональным из-за того, что свойство, которое вы устанавливаете, недействительно, я думаю, что InvalidOperationException полностью приемлемо. Однако в таком сценарии я предполагаю, что свойство должно быть введено через конструктор, поскольку инкапсулирующий объект зависит от этого свойства для выполнения своей единственной ответственности. - person ComeIn; 09.03.2015
comment
Я второй ответ! У меня есть объект, у которого есть метод поиска, и есть свойство, которое говорит поиск двоичный или с помощью грубой силы. Двоичные файлы пока не поддерживаются (т.к. глючат). Поэтому я хочу вызвать исключение, когда для свойства установлено значение binary при вызове метода поиска. Про сеттеров Вадим ничего не сказал. - person Bitterblue; 05.09.2016

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

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

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

person John Fisher    schedule 28.09.2009
comment
Я почти уверен, что в .NET Framework есть классы, которые генерируют исключение ArgumentException из установщика свойства. Не могу вспомнить где именно, но помню, как наткнулся на это. Вы можете возразить, что это может быть некорректно, но, несмотря на то, что структура создала прецедент. - person Tinister; 28.09.2009

Вполне уместно генерировать исключение ArgumentNullException, если кто-то пытается присвоить значение null.

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

person Mark Seemann    schedule 28.09.2009
comment
Откуда вы взяли, что свойство никогда не должно бросать операцию чтения? Конечно, это может произойти достаточно легко. - person John Fisher; 28.09.2009
comment
@John Я не думаю, что он имел в виду, что это не может, но просто не должно. - person Brian Rasmussen; 28.09.2009
comment
@ Джон Фишер: Квалина, Кшистоф и Брэд Абрамс: Рекомендации по разработке рамок. Соглашения, идиомы и шаблоны для многоразовых библиотек .Net, Addison-Wesley, 2006. стр. 121 - среди других источников. - person Mark Seemann; 28.09.2009
comment
Ах. Я, конечно, понимаю, что избегайте генерирования исключений из получателей свойств, но это сильно отличается от того, что никогда не следует .... - person John Fisher; 28.09.2009

Устанавливает ли конструктор ненулевое значение? Если так, то я бы просто кинул ArgumentNullException из сеттера.

person Tinister    schedule 28.09.2009

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

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

person JaredPar    schedule 28.09.2009
comment
Что вы подразумеваете под подробным сообщением для конструктора? У меня должен быть конструктор по умолчанию. - person Vadim; 28.09.2009
comment
@Vadim - подробная причина возникновения исключения аргумента. Например, свойство Blah параметра foo должно быть ненулевым. - person JaredPar; 28.09.2009
comment
@Vadim, он имеет в виду конструктор исключения, а не конструктор вашего объекта. - person bdukes; 28.09.2009

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

Также потребуйте, чтобы свойство было установлено в конструкторе.

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

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

person James Black    schedule 28.09.2009
comment
У меня должен быть конструктор по умолчанию. - person Vadim; 28.09.2009
comment
Вы не можете указать допустимое значение по умолчанию, которое я беру в конструкторе? - person James Black; 28.09.2009
comment
К сожалению, я не могу играть в угадайку. Я понятия не имею, какое значение следует установить во время выполнения. - person Vadim; 28.09.2009
comment
Тогда InvalidOperationException будет вашим лучшим выбором. - person James Black; 28.09.2009

Существует прецедент расширения интерпретации ArgumentNullException до значения «строковый аргумент имеет значение NULL или пусто»: System.Windows.Clipboard.SetText в этом случае вызовет исключение ArgumentNullException.

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

person Joe    schedule 28.09.2009

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

person erikkallen    schedule 28.09.2009