Почему я не могу объявить перечисление, наследуемое от байта, но я могу от байта? - PullRequest
27 голосов
/ 15 февраля 2011

Если я объявляю перечисление вот так ...

public enum MyEnum : byte {
    Val1,
    Val2
}

... это работает.

Если я объявляю перечисление вот так ...

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

... это не работает.Throw компилятора:

ошибка CS1008: введите байт, sbyte, short, ushort, int, uint, long или ulong ожидаемый

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

Ответы [ 6 ]

29 голосов
/ 15 февраля 2011

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

Почему я не могу объявить перечисление, наследуемое от байта, но я могу от байта?

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

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


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

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

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

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

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

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

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

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


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

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


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


Опять же, мы можем догадаться. Я думаю, что перечисления предназначены для фантазии чисел. Символы на практике являются целыми числами в качестве детали реализации, но логически они не являются числами , они являются символами . Мы хотим иметь возможность выполнять операции над перечислениями, такие как флаги сложения, «или» и «и» и т. Д .; В спецификации ясно, что эти операции выполняются так, как если бы они выполнялись для базового типа. Тип char, не являющийся логически числом, определяет не все операторы, которые вам могут понадобиться. И, наконец, если вам нужно двухбайтовое значение перечисления, у вас уже есть short и ushort.


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

Внимательное прочтение спецификации грамматики говорит о том, что «char» является грамматически допустимым базовым типом, но параграф пояснительного текста после грамматики говорит, что «char» не является допустимым базовым типом. Спецификация несовместима?

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

enum-base : целочисленного типа

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

enum-base : целочисленного типа (но не char)

26 голосов
/ 15 февраля 2011

Ну, это согласно спецификации (§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 вместо ключевого слова C # для этих примитивных типов (и string), когда хочу вызвать статический метод.Так что

Int32.TryParse

вместо

int.TryParse.

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

10 голосов
/ 15 февраля 2011

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

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

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


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

2 голосов
/ 23 февраля 2016

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

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

enum SomeEnum : System.Int32
{
    None,
    Some
}

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

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

2 голосов
/ 15 февраля 2011

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

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

Дни Copyenum: byte {Sat = 1, Sun, Mon,Вт, ср, чт, пт};

Допустимые типы для перечисления: байты, байты, короткие, короткие, короткие, целые, длинные или длинные.

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

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

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