Когда подходящее время для создания исключения InvalidOperationException? - PullRequest
4 голосов
/ 27 февраля 2012

Мне кажется, я знаю, что имею в виду, но не совсем уверен ...

Документация Framework описывает тип следующим образом:

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

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

(Касательно: ADO.NET, с другой стороны, требует, чтобы вы явно открывали соединение, с другой стороны, не так однозначно; DataAdapter отклоняется от этого, просто открывая соединение instad, закрывая его снова тогда и только тогда, когда оно был закрыт при входе, и я нахожу это удобным и сделал себе оболочку ADO.NET, которая использует этот шаблон для всего. Конечно, это означает, что я рискую сделать 2 ExecuteNonQuery и без необходимости возвращать промежуточное соединение с пулом, но я все еще могу открывать и закрывать соединение, когда я хочу, и это снижение производительности ничто по сравнению с получением исключения.)

Полагаю, ответ на мой вопрос заключается в том, что ТОЛЬКО в таких четких ситуациях мы должны выбросить исключение. Но какой тип исключения будет наиболее подходящим в следующем сценарии:

</p> <pre> public class FormatterMapping { Dictionary formattersByName = new ...(); public IFormatter GetFormatter(string key) { IFormatter f; if (formattersByName.TryGetValue(key, out f)) return f; else throw new ??Exception("explanation of why this failed."); } } </pre> <p>

Моим первым инстинктом было выбрасывать ArgumentException. Затем я начал думать, что с тем же успехом может быть и то, что в сопоставлении отсутствует ключ, поскольку аргумент «неправильный». По сути, операция «Получить форматтер X» недопустима , потому что X не отображается в отображении, но я не имею понятия, должен ли был там «X» или нет смысла просить X здесь.

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

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

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

Пока никто не убедит меня в обратном, я склоняюсь к ArgumentException. С точки зрения отображения аргумент неверен, поэтому, по крайней мере, есть одна четкая линия аргументации, подтверждающая это. :)

Ответы [ 2 ]

4 голосов
/ 27 февраля 2012

Ни один не идеален, и оба будут в порядке.Или, может быть, вы хотите что-то по-настоящему однозначное:

KeyNotFoundException .

public class FormatterMapping
{
    Dictionary<string, IFormatter> formattersByName = new ...();

    public IFormatter GetFormatter(string key) 
    {
        // validate the argument
        if (!formattersByName.ContainsKey(key))
            throw new KeyNotFoundException("No formatter exists for given key");

        return formattersByName[key];
    }
}

В качестве альтернативы вы можете просто позволить Dictionary <> выбросить его.

Я предлагаю вам выбрать один, документировать его и двигаться дальше.Обычно не стоит тратить много времени на выбор конкретных исключений для броска.Документирование поведения более важно.

3 голосов
/ 27 февраля 2012

Я бы рассмотрел использование ArgumentException для чего-то подобного:

if (string.IsNullOrEmpty(key))
{
    throw new ArgumentException("Expected a key");
}

Для вашего примера я думаю, что подойдет либо InvalidOperationException, либо KeyNotFoundException, либо просто напишите свой, если вы думаете,это подходит.

Моё мнение может не понравиться пуристам, но мои исключения автоматически отправляются мне по электронной почте в системе, в которой я работаю, так что, в конечном счете, в большинстве случаев мне все равно, какой тип Исключения я ловлю, пока могу получить достаточно полезной информации, чтобы увидеть, что произошло.Это включает:

  1. Простое для понимания сообщение об ошибке
  2. Трассировка стека
  3. Внутреннее исключение, если это необходимо
  4. Любая дополнительная информация о контекстебудет дополнительный бонус.Под этим я подразумеваю, что если вы сможете получить какие-либо значения во время создания исключения, это значительно упростит отладку.
...