Какое исключение я должен выдать, чтобы сообщить о внутренней ошибке в моей программе? - PullRequest
19 голосов
/ 23 июля 2010

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

Например:

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 могло возникнуть из-за ошибки в Whither () или недопустимой комбинации любых аргументов и / или текущего состояния экземпляра.

Я ищу что-то такое, как InvalidProgramStateException, InternalErrorException или подобное.

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

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

Ответы [ 7 ]

4 голосов
/ 02 ноября 2012

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

4 голосов
/ 23 июля 2010

А как насчет InvalidOperationException?

2 голосов
/ 10 марта 2016

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

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

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


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

2 голосов
/ 23 июля 2010

Я думаю, что 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);
    }
}

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

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

против

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

1 голос
/ 08 февраля 2011

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

1 голос
/ 23 июля 2010

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

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

  • ArgumentNullException: аргумент нулевой, хотя это запрещено

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

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

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

См. Аналогичный вопрос и ответ, который мне дали.

0 голосов
/ 23 июля 2010

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

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

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