Правильные исключения для использования для нулей - PullRequest
3 голосов
/ 21 мая 2010

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

//constructor
public Main(string arg){
   if(arg==null)
      throw new ArgumentNullException("arg");

  Thing foo=GetFoo(arg);

  if(foo==null)
     throw new NullReferenceException("foo is null");    
}

Это правильный подход для обоих типов исключений?

Ответы [ 9 ]

6 голосов
/ 21 мая 2010

Первое исключение определенно верно.Это второй хитрый способ.

Здесь есть две возможности:

  • GetFoo() не предназначен для возврата нуля, никогда.В этом случае мы в основном доказали ошибку в GetFoo().Я не уверен в лучшем исключении здесь, оставляя ContractException (из Code Contracts) в стороне.По сути, вы хотите что-то как ContractException - исключение, означающее: «Мир сошел с ума: это не просто внешне неожиданный результат, здесь есть ошибка».
  • GetFoo() может законно вернуть null, из-за значения arg.В этом случае я бы предположил, что ArgumentException (но не ArgumentNullException) может быть уместным.С другой стороны, странно бросать ArgumentException после , используя аргумент.

InvalidOperationException здесь не совсем уместно, но я может поддаться искушению использовать его как наиболее близкий к провалу контракта ...

РЕДАКТИРОВАТЬ: Вы также должны рассмотреть возможность создания собственного исключения, согласно ответу Ааронаута.

5 голосов
/ 21 мая 2010

Вы никогда не должны явно бросать NullReferenceException.

Если null было передано в качестве параметра, вы должны бросить ArgumentNullException с именем параметра.
Если какая-то другая вещь - null, вы, вероятно, должны выбросить InvalidOperationException с описательным сообщением.

3 голосов
/ 21 мая 2010

Никогда не бросайте NullReferenceException. Это не значит, что ноль был принят. Это означает, что была попытка использовать ноль.

1 голос
/ 21 мая 2010

В блоге Code Analysis , использование исключений должно быть следующим:

  • ArgumentOutOfRangeException, если тестируемое вами входное значение не соответствует ожидаемому набору значений. (например, если параметр представляет имя команды, а предоставленное имя команды недействительно)

  • ArgumentNullException, если входное значение не может быть нулевым для выполнения функции.

  • ArgumentException, если введенное значение недопустимо (например, если вы передаете пустую строку, но пустые строки не допускаются)

1 голос
/ 21 мая 2010

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

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

  • ArgumentException подразумевает, что сам аргумент каким-то образом недопустим; это не совсем так. Аргумент был в порядке, просто что-то неожиданное случилось позже.

  • InvalidOperationException является почти правильным, но это исключение обычно интерпретируется как означающее, что операция была вызвана в неправильное время, например, попытка выполнить команду в соединении, которое не ' еще не было открыто. Другими словами, это указывает на несоответствие между текущим состоянием объекта и конкретной операцией, которую вы пытались выполнить; это действительно не применимо и здесь.

  • NullReferenceException прямо сейчас. Это зарезервированное исключение, которое означает что-то совершенно другое (что программа фактически пыталась почтить нулевая ссылка).

Ничего из этого не верно. То, что вам действительно нужно сделать, это сообщить , в частности , что пошло не так, и для того, чтобы сделать это, вы должны создать MissingThingException. Это исключение может включать идентификатор предмета (предположительно arg) в его сообщении / детали. Это лучше всего подходит для вызывающих абонентов, поскольку позволяет им перехватить конкретное исключение, если они знают, как его обработать, а также лучше всего подходит для конечных пользователей, поскольку позволяет оставлять значимое сообщение об ошибке.

Сводка: для этого создайте собственный класс исключений.

1 голос
/ 21 мая 2010

ArgumentNullException * * 1004

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

NullReferenceException:

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

"foo is null" - плохое сообщение об ошибке, поскольку foo является локальной переменной . Лучшее сообщение об ошибке будет "GetFoo returned null for the input " + arg. Кроме того, если исключение будет выдано всякий раз, когда GetFoo возвращает ноль, заставьте его выдать соответствующее исключение.

1 голос
/ 21 мая 2010

ArgumentNullException - очевидный выбор для первой проверки.

Поскольку представляется, что Thing является производным от входного параметра, я бы выбросил ArgumentException, чтобы указать, что Thing не может быть создан из указанного ввода. В конце концов, это (предположительно в любом случае) проблема с вводом, а не алгоритм, используемый для построения Thing.

1 голос
/ 21 мая 2010

ArgumentNullException, очевидно, правильно и для второго зависит от вашего бизнес-контекста.

0 голосов
/ 21 мая 2010

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

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