X - это перечисление - это согласно спецификации?

Проверить, является ли объект перечислением, обсуждает проверку объекта с помощью is Enum, чтобы увидеть, содержит ли он значение перечисления.

Это указано где-нибудь в спецификации? Запись is (7.10.10 в версии 4.0) перечисляет следующие возможные правые значения:

  • анонимная функция
  • группа методов
  • нулевой
  • ссылочный тип ** Это может быть перечисление?
  • обнуляемый тип
  • ненулевой тип значения ** Это может быть перечисление?

Предполагая, что значение перечисления соответствует «ссылочному типу» из приведенного выше списка, в спецификации указано следующее:

... результат верен, если D [динамический тип RHS)] и T [LHS] имеют один и тот же тип, если D является ссылочным типом и существует неявное преобразование ссылки из D в T, или если D является существует тип значения и преобразование бокса из D в T.

Являются ли какие-либо из этих условий строго верными в случае is Enum? Компилятор не поддерживает, скажем, is class или is struct.

Так поддержка is Enum соответствует спецификации или это решение реализации?


person sq33G    schedule 07.02.2012    source источник
comment
Что заставляет вас думать, что значение перечисления является ссылочным типом?   -  person BoltClock    schedule 07.02.2012
comment
@BoltClock: Потому что так сказано в коде! typeof(Enum).IsValueType => false   -  person leppie    schedule 07.02.2012
comment
Вы специально спрашиваете о типе Enum или определенных пользователем перечислениях? Кажется, есть небольшая путаница (включая меня; p)   -  person leppie    schedule 07.02.2012
comment
Как бы у вас был экземпляр Enum? Это более или менее абстрактный класс.   -  person sq33G    schedule 08.02.2012


Ответы (4)


Нет поддержки is class или is struct, потому что нет общего базового типа, который отличал бы классы или структуры от других типов. is Enum работает, потому что System.Enum — это фактический тип, который база всех перечислений. А Enum — это ссылочный тип, поэтому применяется последняя часть:

если D является типом значения и существует преобразование упаковки из D в T

D (тип выражения слева) — это тип значения. А T — это Enum, который является базовым типом D. Таким образом, происходит преобразование D в Enum, поэтому значение выражения равно true.

Упаковочное преобразование из любого перечисления в Enum явно указано в §14.4. Тип System.Enum:

Тип System.Enum является абстрактным базовым классом всех типов перечисления (он отличается от базового типа перечисления), а члены, унаследованные от System.Enum, доступны в любом типе перечисления. Преобразование упаковки существует из любого типа перечисления в System.Enum, а преобразование распаковки существует из System.Enum в любой тип перечисления.

Обратите внимание, что System.Enum сам по себе не является перечисленным типом. Скорее, это тип-класс, из которого происходят все типы-перечисления. Тип System.Enum наследуется от типа System.ValueType, который, в свою очередь, наследуется от типа object. Во время выполнения значение типа System.Enum может быть нулевым или ссылкой на упакованное значение любого типа перечисления.

person svick    schedule 08.02.2012

Enum — это ссылочный тип.

typeof(Enum).IsValueType => false

Интересно,

typeof(ValueType).IsValueType => false
person leppie    schedule 07.02.2012
comment
Да, я просто просматривал сайт msdn -› msdn.microsoft.com /en-us/library/system.enum.aspx. Enum наследуется от ValueType, который наследуется от Object. Все это классы и, следовательно, ссылочные типы. По-видимому, были некоторые проблемы с .IsClass в фреймворках до .NET 4 -> stackoverflow.com/questions/1661913/. - person Craig Wilson; 07.02.2012
comment
@CraigWilson: Интересная «ошибка». 99,9% времени меня интересует только .IsValueType :) - person leppie; 07.02.2012

Enum — это фактический тип, а класс и структура — нет. Следовательно, Enum можно использовать с правой стороны, тогда как класс и структура не могут.

person Craig Wilson    schedule 07.02.2012
comment
Не совсем. Вы сами себе противоречите :) - person leppie; 07.02.2012
comment
интересно... ну, хм... а где Эрик Липперт... возможно, он сможет ответить на этот вопрос... - person Craig Wilson; 07.02.2012
comment
@leppie, нет никакого противоречия. System.Enum является фактическим типом. Для классов или структур такого типа нет. Есть System.ValueType, но это основа для всех типов значений, а не только для структур. - person svick; 08.02.2012

О чем здесь спрашивают, мне не совсем ясно, но я надеюсь, что теперь понял.


Учитывая приведенный ниже код:

void F(Object obj) {
  var isEnum obj is Enum;
  ...
}

В каких частях стандарта C# указано, что isEnum истинно, когда obj является экземпляром перечисляемого типа?


В 14.9.10 это оператор в Спецификация языка C# содержит пять пунктов, описывающих, как он оценивается:

  • Первый пункт касается случаев, когда obj имеет более конкретный тип, чем System.Object.

  • Второй пункт касается типов, допускающих значение NULL.

  • Четвертая пуля посвящена универсальным типам.

  • Пятая пуля — это когда совпадений нет, а оператор is оценивается как false, чего, как мы знаем, нет.

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

  • 1-й подпункт применяется, когда obj равно нулю.

  • Второй подпункт посвящен типам, допускающим значение NULL.

  • Четвертый подпункт — это когда совпадений нет, а оператор is оценивается как false, чего, как мы знаем, нет.

Вы ожидаете, что применяется третий подпункт:

В противном случае пусть R будет типом времени выполнения экземпляра, на который ссылается e. Если R и T имеют один и тот же тип, если R является ссылочным типом и существует неявное преобразование ссылки из R в T, или если R является типом значения, а T является типом интерфейса, реализованным R, результат будет истинным.

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

  • R и T не одного типа, потому что R — это MyEnum, а T — это System.Enum.

  • R — это MyEnum, который является типом значения (11.1.9), а не ссылочным типом.

  • T — это System.Enum, который не является типом интерфейса.

Я не хочу утверждать, что в спецификации есть ошибка, но после подробного прочтения 14.9.10 я не могу понять, как is Enum может быть оценено как true, учитывая коробочную ссылку на тип перечисления.

Зная, что люди, занимающиеся стандартами, в целом намного умнее меня, я, вероятно, что-то упустил из виду, но даже если бы я этого не сделал, это не должно мешать вам использовать is Enum для проверки того, является ли тип перечислением. Я уверен, что это не деталь реализации, которую можно использовать таким образом.

person Martin Liversage    schedule 07.02.2012
comment
@leppie: Ваше утверждение верно, но я не говорю о типе Enum. Я говорю о перечислениях, и typeof(MyEnumeration).IsValueType равно true для любого MyEnumeration, которое вы определяете ключевым словом enum. - person Martin Liversage; 07.02.2012
comment
Но вопрос касается Enum, а не MyEnum. Я неправильно прочитал вопрос? - person leppie; 07.02.2012
comment
Я прочитал этот вопрос, так как где в спецификации объясняется, почему X is Enum == true когда X является перечислением? - person Martin Liversage; 07.02.2012
comment
Я не отрицаю, что значение перечисления может быть приведено к Enum - я спрашиваю, как маркированный список сразу после абзаца, который вы цитируете из спецификации, охватывает этот случай. Точно так же я не понимаю, как это относится к делу 3 is object. - person sq33G; 08.02.2012
comment
В версии спецификации ECMA, которую вы используете, применяется первый пункт: существует упаковывающее преобразование из любого типа перечисления в Enum. - person svick; 08.02.2012
comment
@svick: тип времени компиляции obj равен System.Object, поэтому я не понимаю, как применяется первый пункт. Если я правильно понимаю первую пулю, критерии могут быть оценены во время компиляции, а не во время выполнения. - person Martin Liversage; 08.02.2012
comment
@MartinLiversage, ты прав, я пропустил это. Кажется, это действительно ошибка в этой версии спецификации. Однако спецификация С# 4 имеет это правильно. - person svick; 08.02.2012