Редактировать : комментарии внизу. Также это .
Вот что меня смущает. Насколько я понимаю, если у меня есть такое перечисление ...
enum Animal
{
Dog,
Cat
}
... то, что я по существу сделал, определено типом значения , называемым Animal
с двумя определенными значениями, Dog
и Cat
. Этот тип является производным от ссылочного типа System.Enum
(то, что типы значений обычно не могут делать - по крайней мере, в C # - но это разрешено в этом случае), и имеет средство для возврата и вперед / от int
значений.
Если бы способ, которым я только что описал тип перечисления выше, был верным, то я ожидал бы, что следующий код выдаст InvalidCastException
:
public class Program
{
public static void Main(string[] args)
{
// Box it.
object animal = Animal.Dog;
// Unbox it. How are these both successful?
int i = (int)animal;
Enum e = (Enum)animal;
// Prints "0".
Console.WriteLine(i);
// Prints "Dog".
Console.WriteLine(e);
}
}
Как правило, вы не можете распаковать тип значения из System.Object
как что-либо, кроме его точного типа . Итак, как это возможно? Это как если бы Animal
тип был int
(не только конвертируемый в int
), а - Enum
(не только конвертируемый в Enum
) одновременно. Это множественное наследование? System.Enum
как-то наследуется от System.Int32
(что-то, чего я не ожидал, возможно)?
Редактировать : Это не может быть ни одним из вышеперечисленных. Следующий код демонстрирует это (я думаю) убедительно:
object animal = Animal.Dog;
Console.WriteLine(animal is Enum);
Console.WriteLine(animal is int);
Вышеуказанные выходы:
True
False
Как в документации MSDN по перечислениям , так и в спецификации C # используется термин "базовый тип"; но я не знаю, что это значит, и никогда не слышал, чтобы это использовалось в отношении чего-либо, кроме перечислений. Что на самом деле означает «базовый тип» ?
Итак, это еще один случай, который получает специальную обработку от CLR ?
Мои деньги в этом случае ... но ответ / объяснение было бы неплохо.
Обновление : Damien_The_Unbeliever предоставил ссылку, чтобы действительно ответить на этот вопрос. Объяснение можно найти в Разделе II спецификации CLI, в разделе о перечислениях:
Для обязательных целей (например, для
найти определение метода из
ссылка на метод используется для его вызова)
Перечисления должны отличаться от их
базовый тип. Для всех остальных
цели, включая проверку и
выполнение кода, перечисление без коробки
свободно взаимодействует с его
базовый тип . Перечисления могут быть в штучной упаковке
в соответствующий штучной упаковке
тип, но этот тип не то же самое
в штучной упаковке типа основного
типа, чтобы бокс не потерял
оригинальный тип перечисления.
Редактировать (снова?!) : Подождите, на самом деле, я не знаю, правильно ли я прочитал это в первый раз. Возможно, это не на 100% объясняет само специализированное поведение при распаковке (хотя я оставляю ответ Дэмиена как принятый, поскольку он пролил много света на эту проблему). Я продолжу изучать это ...
Еще один правка : Чувак, тогда ответ yodaj007 бросил меня на еще одну петлю. Каким-то образом перечисление не совсем то же самое, что и int
; все же int
можно присвоить переменной enum без приведения ? Буг?
Я думаю, что все это в конечном итоге освещается ответом Ганса , поэтому я принял его. (Извини, Дэмиен!)