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

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

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

Скажем, у нас есть SomeEnum и оператор switch, обрабатывающий его как:

enum SomeEnum
{
  One,
  Two
}

void someFunc()
{
  SomeEnum value = someOtherFunc();
  switch(value)
  {
     case One:
       ... break;
     case Two:
       ... break;
     default:
         throw new ??????Exception("Unhandled value: " + value.ToString());    
  }
}

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

Мой вопрос: какое правильное исключение в таких обстоятельствах, когда вы хотите уведомить, что данный код не обрабатывается/не реализован или его никогда не посещали? Раньше мы использовали NotImplementedException, но, похоже, он не подходит. Наш следующий кандидат InvalidOperationException, но этот термин звучит не так. Какой правильный и почему?

4b9b3361

Ответ 1

Поскольку это внутренняя операция, которая терпит неудачу (выдает что-то недействительное), InvalidOperationException - это путь.

Документы просто говорят:

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

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

Ответ 2

Лично я добавляю настраиваемое исключение в свой проект:

public class UnexpectedEnumValueException<T> : Exception
{
    public UnexpectedEnumValueException( T value )
        : base( "Value " + value + " of enum " + typeof( T ).Name + " is not supported" )
    {
    }
}

Тогда я могу просто по мере необходимости:

enum SomeEnum
{
  One,
  Two
}

void someFunc()
{
  SomeEnum value = someOtherFunc();
  switch(value)
  {
   case SomeEnum.One:
    ... break;
   case SomeEnum.Two:
    ... break;
   default:
      throw new UnexpectedEnumValueException<SomeEnum>(value);    
  }
}

Таким образом, я могу выполнить поиск "UnexpectedEnumValueException <SomeEnum> " когда я, например, добавляю новое значение в SomeEnum, и я хочу найти все место, на которое может повлиять изменение. Сообщение об ошибке намного более понятно, чем общее исключение.

Ответ 3

Попробуйте использовать Класс InvalidEnumArgumentException

void someFunc()
{
  SomeEnum value = someOtherFunc();
  switch(value)
  {
     case One:
       ... break;
     case Two:
       ... break;
     default:
          throw new InvalidEnumArgumentException(); 
  }
}

Ответ 4

Я думаю, что это зависит от семантики, представленной перечислением.

InvalidOperationException подходит, если оно представляет состояние объекта.

NotSupportedException является подходящим, если он представляет функцию приложения, которая не поддерживается.

NotImplementedException подходит для функции приложения, которая в настоящее время не реализована, но может быть в будущей версии.

...

Ответ 5

Предложение Resharper для случая переключения:

switch(parameter)
{
   default:
      throw new ArgumentOutOfRangeException("parameter");
}

Но это не соответствовало вашим потребностям. Если нет, вы можете определить настраиваемый тип исключения в отношении того, что выполняется в этой функции: SomeEnumOutOfRangeException...

Ответ 6

Если новое значение добавляется, и вы забыли его обработать где-нибудь, это ошибка программирования или Boneheaded Exception как Eric Lippert называет их. Я создаю свой собственный класс BoneheadedException, который я бросаю всякий раз, когда обнаруживаю ошибку программирования, для которой больше не подходит тип исключения FCL.

Ответ 7

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

Если вы используете словарь, то, если вы попытаетесь проиндексировать словарь со значением, которое не было учтено, вы получите KeyNotFoundException, и больше нет причины спрашивать: "Что мне делать? в случае по умолчанию?".

Ответ 8

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

case One:
   ... break;
 case Two:
   ... break;
 default:
    throw new ContractViolationException("Invalid enum");

Ответ 9

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