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

Есть ли способ заставить компилятор С# испускать ошибку, если у коммутатора (enum_val) отсутствует оператор case?

Я только что понял, что добавил значение в список значений "must-handle" в моем перечислении, но я не заметил его до выполнения. Я знаю, что компилятор С# действительно эффективен, когда дело доходит до размышлений и самоанализа типов, поэтому мне было интересно, есть ли способ заставить оператор switch/case покрыть все возможные значения enum?

Пример:

enum Colors
{
   Red,
   Blue,
   Green,
   Yellow
};

Colors c = ...;

switch (c)
{
   case Colors.Red:  // No error, Red is a Color
      break;
   case Colors.Blue:
   case Colors.Green:  // No error, Blue and Green handled as well
      break;
}  // whoops! "error: 'Colors.Yellow' unhandled"
   // or even, "error: no 'default' and 'Colors.Yellow' unhandled"

Я хочу решение для компиляции.

4b9b3361

Ответ 1

Просто, выбросив (каламбур непредвиденный), вы можете заменить Switch-Case на словарь (Func<int,int> в качестве примера):

Dictionary<Colors,Func<int,int>> d = new Dictionary<Colors, Func<int, int>>();
d.Add(Colors.Red, (x) => x+1);
d.Add(Colors.Blue, (x) => x+1);
d.Add(Colors.Green, (x) => x+1);
foreach (Colors color in Enum.GetValues(typeof(Colors)))
{
    if (!d.ContainsKey(color))
    {
        throw new Exception("Poor color " + color + " ignored");
    }
}

Ответ 2

Нет никакого способа компиляции, чтобы это произошло. Однако очень ОЧЕНЬ простой ответ заключается в том, чтобы иметь обработчик default, который просто генерирует исключение по строкам, "эта опция не обрабатывалась, boo".

switch (c)
{
    case Colors.Red:  // no error, Red is a Color
        break;
    case Colors.Blue:
    case Colors.Green:  // no error, Blue and Green handled as well
        break;
    default:
        throw new Exception("Unhandled option: " + c.ToString());
}

Ответ 3

Вы можете использовать SwitchEnumAnalyzer, чтобы получать предупреждения о компиляторе такого типа. Я просто использовал его в своем проекте, и он работает хорошо. Как и в любом анализаторе Roslyn, вы можете выбрать уровень уведомления - если это должно быть просто предупреждение или правильная ошибка.

Ответ 4

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

    [Test]
    public void CheckThatAllEnumCoveredInSwitchCase()
    {

        foreach (var singleEnum in Enum.GetValues(typeof(YOURENUM)))
        {
                myclass.methodofswitchcase((YOURENUM)singleEnum);
        }

    }

Ответ 5

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

enum MyEnum {A, B};

class TestEnum
{
    // Static constructor
    static TestEnum()
    {
        // Check if this code needs updating as the enum has changed
        if (Enum.GetNames(typeof(MyEnum)).Length != 2)
        {
            // If this fails update myFunction and the number above
            throw new Exception("Internal error - code inconsistency");
        }
    }

    // My function that switches on the enum
    string myFunction(MyEnum myEnum)
    {
        switch (myEnum)
        {
            case MyEnum.A: return "A";
            case MyEnum.B: return "B";
        }
        throw new Exception("Internal error - missing case");
    }
}

Это приведет к исключению из статического конструктора, если количество элементов в перечислении будет изменено. Поэтому разработчик знает, что ему нужно обновить код. Вы даже можете сделать эту проверку с unit test, который вы запускаете со своей сборкой.

Ответ 7

Для С++ вы можете заставить компилятор выдать предупреждение, добавив в список параметров компилятора /we 4061. Надеюсь это поможет.:)

http://msdn.microsoft.com/en-us/library/thxezb7y.aspx

http://msdn.microsoft.com/en-us/library/96f5t7fy (v = vs .80).aspx

На самом деле я ошибся в этом; похоже, вы можете заставить компилятор выдать ошибку. Просто скомпилируйте /Wall/we 4061. Я не пробовал это сам, но, читая приведенные выше страницы MSDN, похоже, что это должно работать.