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

Почему я не могу объявить enum, наследующий от Byte, но могу из байта?

Если я объявляю перечисление вроде этого...

public enum MyEnum : byte {
    Val1,
    Val2
}

... он работает.

Если я объявляю перечисление вроде этого...

public enum MyEnum : System.Byte {
    Val1,
    Val2
}

... он не работает. Бросок компилятора:

ошибка CS1008: тип байта, sbyte, short, ushort, int, uint, long или ulong ожидается

Как байт является псевдонимом фактического типа, System.Byte, почему я не могу использовать второе объявление?

4b9b3361

Ответ 1

Ну, это согласно спецификации (§14.1). В грамматике указано, что произведение enum-declaration равно

enum-declaration:
    attributes_opt   enum-modifiers_opt   enum   identifier   enum-base_opt   enum-body   ;_opt

где

enum-base является

:integral-type

и

integral-type:
sbyte
byte
short
ushort
int
uint
long
ulong
char

Что касается того, почему спецификация такова, это не ясно.

Обратите внимание, что char указан как терминал для integral-type, но спецификация явно заявляет, что

Обратите внимание, что char не может использоваться как базовый тип.

Кстати, я действительно считаю, что лучше всего использовать псевдонимы. Я использую только имя .NET вместо ключевого слова С# для этих примитивных типов (и string), когда я хочу вызвать статический метод. Так

Int32.TryParse

вместо

int.TryParse.

В противном случае я говорю, например, typeof(int), а не typeof(Int32).

Ответ 2

Здесь возникает ряд вопросов.

Почему я не могу объявить enum, наследующий от Byte, но могу из байта?

Как отмечали другие, это то, о чем говорится в спецификации.

Записи комитета по дизайну языка не оправдывают это решение. В заметках от июня 2000 года говорится


Ключевые слова для предопределенных типов (например, int) и их соответствующие имена типов (например, Int32) могут в основном, но не полностью использоваться взаимозаменяемо. Мы обсудили, хотим ли мы внести какие-либо изменения в эту область. Мы не сделали.

Вот список мест, где они не являются взаимозаменяемыми.

  • "int" может использоваться как базовый тип для перечислений; Int32 не может.
  • Объявления псевдонима не могут использовать ключевые слова.

Некоторые мои размышления по этому вопросу:

Первое, что приходит в голову, это то, что каждый раз, когда вы даете пользователю выбор, вы даете им возможность написать ошибку, и каждый раз, когда вы даете им возможность написать ошибку, вы должны сделать сообщение об ошибке для этого. Если мы допустили "перечисление X: байт", тогда мы даем разумное сообщение об ошибке, когда пользователь случайно удалил "using System;". Мы можем избежать этой путаницы и всех затрат на разработку и тестирование эвристики, сообщающей об ошибках, просто не допуская выбора в первую очередь.

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

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

ОБНОВЛЕНИЕ: Я только что спросил одного из людей, которые были в комнате в тот день, было ли что-то, что я пропустил в своих размышлениях, и он сказал, что да, они подумали об этом и решили, что полный анализ типов - это работа для команда разработчиков, испытаний и обслуживания, работа, которая не покупала пользователя ничего ценного. (Он также отметил, что у них были аналогичные аргументы в отношении System.Void: должно ли быть законным говорить "public static System.Void Main (string [] args)" например? Опять же, они решили, что это не добавило значения для пользователей, но добавить потенциальную двусмысленность и работать для команды.)


Почему "char" не является легальным базовым типом?

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


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


Опять же, мы можем догадаться. Я предполагаю, что перечисления предназначены для причудливых чисел. Шары на практике представляют собой целые числа в качестве детали реализации, но логически они не являются числами, они являются символами. Мы хотим иметь возможность делать операции с перечислениями, такими как добавление, флажки "или-ing" и "and-ing" и т.д.; спецификация ясно, что эти операции выполняются так, как если бы они выполнялись по базовому типу. Тип char, не логически являющийся числом, не определяет всех операторов, которые могут вам понадобиться. И, наконец, если вы хотите двухбайтовое значение перечисления, то у вас уже есть короткие и удобные в вашем распоряжении.


Связанный вопрос из письма по этому вопросу:

Тщательное чтение спецификации грамматики говорит о том, что "char" является грамматически легальным базовым типом, но абзац объяснительного текста после грамматики говорит о том, что "char" не является легальным базовым типом. Является ли спецификация непоследовательной?

Да. Я не теряю сон над ним. Если это заставляет вас чувствовать себя лучше, представьте, что грамматическая строка, в которой говорится

enum-base: интегральный тип

вместо этого читает

enum-base: интегральный тип (но не char)

Ответ 3

Самый простой ответ - "так, как он указал". (Это в разделе 14.1 спецификации С# 4. Нумерация может отличаться для других версий.)

Спецификация не дает какой-либо конкретной причины для этого 1 но, возможно, легче описать имена псевдонимов интегрального типа (которые являются всеми ключевыми словами), чем сказать, что это может быть любой тип, который разрешает (с помощью псевдонимов другого типа, таких как директивы using) в один из определенных наборов.

Есть ли у вас причина для использования System.Byte вместо этого?


1 В аннотированной спецификации С# 4 есть одна аннотация в этом разделе... но она была написана мной и просто указывает, что это одно из немногих мест в спецификации, где вы действительно не могут заменить псевдонимы обычными именами типов. Поэтому не очень полезно для этого вопроса:)

Ответ 4

Вот ответ, по крайней мере частично, из MSDN:

Каждый тип перечисления имеет базовый тип, который может быть любым интегральный тип, кроме char. По умолчанию базовый тип перечисления Элементы - int. Чтобы объявить перечисление другой интегральный тип, такой как байт, использовать двоеточие после идентификатора за которым следует тип, как показано в следующий пример.

Дни копирования: байт {Сб = 1, Вс, Пн, Вт, Ср, Чт, Пт};

Утвержденный типы для перечисления - это байт, sbyte, short, ushort, int, uint, long или ULONG.

Ответ 5

Только для информации:

С новым компилятором Roslyn этот код

enum SomeEnum : System.Int32
{
    None,
    Some
}

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

Пример в dotnetfiddle, где вы можете выбрать компилятор: https://dotnetfiddle.net/oXyAgV

Ответ 6

Похоже, что он не принимает имена реальных типов, а только ключевые слова языка.