Изменить: комментарии внизу. Кроме того, this.
Вот что меня смущает. Я понимаю, что если у меня есть перечисление вроде этого...
enum Animal
{
Dog,
Cat
}
... то, что я по существу сделал, определяется тип значения, называемый Animal
с двумя определенными значениями, Dog
и Cat
. Этот тип происходит от ссылочного типа System.Enum
(то, что обычно не подходит для типов значений, по крайней мере, не в С#, но это разрешено в этом случае), и имеет возможность для отбрасывания назад и вперед в/из 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
a int
(не просто конвертируемый в int
), а - a Enum
(не просто конвертируемый в Enum
) в то же время. Является ли это множественным наследованием? Может ли System.Enum
наследовать от System.Int32
(что-то, чего я не ожидал бы быть возможным)?
Изменить. Это не может быть ни один из приведенных выше. Следующий код демонстрирует это (я думаю) окончательно:
object animal = Animal.Dog;
Console.WriteLine(animal is Enum);
Console.WriteLine(animal is int);
Вышеуказанные выходы:
True False
Оба документация MSDN по перечислениям и спецификация С# используют термин "базовый тип"; но я не знаю, что это значит, и я никогда не слышал, чтобы он использовался в отношении чего-либо другого, кроме перечислений. Что означает "базовый тип"?
Итак, это еще один случай, который получает специальное обращение с CLR?
Мои деньги в этом случае... но ответ/объяснение будет приятным.
Обновить: Damien_The_Unbeliever предоставил ссылку, чтобы действительно ответить на этот вопрос. Объяснение можно найти в разделе II спецификации CLI в разделе об перечислениях:
Для целей связывания (например, для определение определения метода из метод, используемый для его вызова) перечисления должны отличаться от их базовый тип. Для всех остальных целей, включая проверку и выполнение кода, unboxed enum свободно взаимодействует с базовый тип. Перечисления могут быть в коробке к соответствующему экземпляру в коробке тип, но этот тип не тот же как бокс-тип лежащего в основе типа, поэтому бокс не теряет оригинальный тип перечисления.
Изменить (снова?!): Подождите, на самом деле, я не знаю, что я правильно прочитал это в первый раз. Возможно, это не на 100% объясняет специфическое поведение unboxing (хотя я оставляю ответ Damien как принятый, так как он пролил много света на эту проблему). Я буду продолжать изучать это...
Другое Edit: Man, затем yodaj007 ответ бросил меня в другой цикл. Каким-то образом перечисление не совсем то же самое, что и int
; но int
можно присвоить переменной перечисления без заливки? Буг?
Я думаю, что это в конечном итоге освещено Хансом, поэтому я его принял. (Извините, Дэмиен!)