Невозможно неявно преобразовать значение из enum, даже если указан базовый тип

#c# #.net #enums

#c# #.net #перечисления

Вопрос:

В следующем примере кода я определяю enum и указываю его базовый тип как byte. Затем я пытаюсь присвоить значение в байтах и включить значения перечисления, но получаю сообщение об ошибке: Cannot implicitly convert type 'CmdlnFlags' to 'byte'. An explicit conversion exists (are you missing a cast?)

Код:

 using System;

public enum CmdlnFlags: byte {
    ValA = (byte)'a',
    ValB = (byte)'b',
}

public class Sample {
    public static void Main() {
        byte switchByte = CmdlnFlags.ValB;
        switch (switchByte) {
            case CmdlnFlags.ValA: Console.WriteLine('A'); break;
            case CmdlnFlags.ValB: Console.WriteLine('B'); break;
        }
        Console.ReadKey();
    }
}
  

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

Если я приведу, все заработает. Пример:

         byte switchByte = (byte)CmdlnFlags.ValB;
        switch (switchByte) {
            case (byte)CmdlnFlags.ValA: Console.WriteLine('A'); break;
            case (byte)CmdlnFlags.ValB: Console.WriteLine('B'); break;
        }
  

Ответ №1:

Вы должны выполнить приведение, чтобы убедиться, что это действительно то, что вы хотите сделать. Это функция безопасности типов.

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

Иногда это может быть неприятно, но в конечном итоге это хорошо.

Но почему вы все равно выполняете кастинг перед переключением? Просто включите фактические значения enum:

 CmdlnFlags switchFlag = CmdlnFlags.ValB;
switch (switchFlag) {
    case CmdlnFlags.ValA: Console.WriteLine('A'); break;
    case CmdlnFlags.ValB: Console.WriteLine('B'); break;
}
  

Здесь вы не действительно хотите обрабатывать флаг как байт — вы хотите обрабатывать его как флаг и включать его. Так что это именно то, что вы должны сделать.

Комментарии:

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

2. @Sergio: Нет, enum — это отдельный тип. Что именно вы подразумеваете под «вне области объявления»?

3. Фрагмент кода — это просто то, что я создал в компиляторе Snippet, чтобы быстро показать некоторые сценарии. 1 Отличный момент в отношении представления перечислений как отдельных типов. Хотя я все еще не понимаю смысла указывать базовый тип, если вам все равно придется обрабатывать его в детских перчатках позже?

4. @Paul: Думайте об этом как о структуре с единственным полем базового типа. Это не то же самое, что базовый тип, но это решает, что он может хранить.

5. @Joshua: Почему бы не иметь два свойства, оба предоставляющие одни и те же данные, но одно с приведением либо к типу enum, либо из него? Тогда у вас было бы одно свойство для каждого свойства, а не оно «засоряло» вашу кодовую базу.

Ответ №2:

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

     CmdlnFlags switchValue = CmdlnFlags.ValB;
    switch (switchValue) {
         case CmdlnFlags.ValA: Console.WriteLine('A'); break;
         case CmdlnFlags.ValB: Console.WriteLine('B'); break;
     } 
  

Приведения необходимы для обеспечения правильного проектирования программы. Обычно вы не захотите использовать enum в качестве числового значения.