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

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

Какое исключение я должен использовать, когда программа достигает логического состояния, которое я "знаю" не произойдет, и если это произойдет, что-то ужасно плохо.

Например:

int SomeFunction(int arg) {
    SomeEnum x = Whatever(arg, somePrivateMember);
    switch (x) {
        case SomeEnum.Value1:
            return SomeFunction1();
        case SomeEnum.Value1:
            return SomeFunction2();
        default:
            throw new WhatTypeToThrow();
    }
}

Ясно, что ArgumentException является длинным, потому что неверное значение для x могло возникнуть из-за ошибки в Whatever() или недопустимой комбинации любых аргументов и/или текущего состояния экземпляра.

Я ищу что-то вроде InvalidProgramStateException, InternalErrorException или аналогичного.

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

Изменить: Удален простой пример кода, чтобы уменьшить количество ответов ArgumentException.

4b9b3361

Ответ 1

Как насчет InvalidOperationException?

Ответ 2

Почему не исключение InvalidEnumArgumentException? Похоже, что он был специально разработан для этого прецедента.

Ответ 3

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

switch (test)
{
    case SomeEnum.Woo:
        break;
    case SomeEnum.Yay:
        break;
    default:
    {
        string msg = string.Format("Value '{0}' for enum '{1}' is not handled.", 
            test, test.GetType().Name);

        throw new ArgumentOutOfRangeException(msg);
    }
}

Очевидно, что сообщение относится к вашим собственным вкусам, но основы в этом. Добавление значения перечисления в сообщение полезно не только для подробного описания того, какой известный член перечисления не обрабатывался, но также и при наличии недопустимого перечисления, то есть старой проблемы (666) SomeEnum.

Значение "OhNoes" для перечисления "SomeEnum" не обрабатывается.

против

Значение "666" для перечисления "SomeEnum" не обрабатывается.

Ответ 4

Не бросайте какой-либо конкретный тип исключения в код, который вы просматриваете. Вызовите Trace.Assert, или в этом случае даже Trace.Fail, чтобы получить аналогичный эффект для Debug.Assert, кроме включенного даже в версиях (при условии, что настройки не изменены).

Если прослушиватель трассировки по умолчанию, тот, который предлагает пользовательский интерфейс, который предлагает убить всю программу или запустить отладчик, не подходит для ваших нужд, настройте пользовательский прослушиватель трассировки в Trace.Listeners, который вызывает тип закрытого исключения, когда вызывается Trace.Fail (в том числе, когда сбой Trace.Assert).

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


Еще один ответ упоминал Кодовые контракты уже как альтернативу. Аналогично: вы можете вызвать Contract.Assert(false). Это делает тот же подход, что и его настраиваемое, что происходит, если утверждение терпит неудачу, но в этом случае поведение по умолчанию заключается в том, чтобы генерировать исключение, опять же типа, который не доступен извне. Однако, чтобы максимально использовать контракты с кодами, вы должны использовать статический перезаписыватель, который имеет как плюсы, так и минусы, которые я не буду здесь вводить. Если для вас плюсы перевешивают минусы, то непременно используйте их. Если вы предпочитаете избегать статического переписывающего устройства, то я бы рекомендовал полностью исключить класс Contract, так как совершенно не очевидно, какие методы работают и не работают.

Ответ 5

Вот предложения, которые мне дали:

  • ArgumentException: что-то не так со значением

  • ArgumentNullException: аргумент равен null, пока это не разрешено

  • ArgumentOutOfRangeException: аргумент имеет значение вне допустимого диапазона

В качестве альтернативы выведите собственный класс исключений из ArgumentException.

Вход недействителен, если он недействителен в любое время. Хотя вход неожиданно, если он недействителен для текущего состояния системы (для которого InvalidOperationException является разумным выбором в некоторых ситуациях).

См. похожие вопросы и ответы, которые мне дали.

Ответ 6

Вам следует рассмотреть возможность использования кодовых контрактов, чтобы не только генерировать исключения в этом случае, но и документировать, что такое неудавшееся предположение, возможно, с дружеским сообщением программисту. Если вам повезло, функция, которую вы вызвали (Whatever), имела бы Contract.Ensures, которая могла бы уловить эту ошибку, прежде чем вы ее наделите.

Ответ 7

"достигает логического состояния, которое я" знаю "не произойдет, и если это произойдет, что-то ужасно плохо".

В этом случае я бы бросил ApplicationException, запишите, что вы можете, и выйдите из приложения. Если что-то происходит, вы, конечно же, не должны пытаться восстановиться и/или продолжить.