Почему распаковка перечислений дает странные результаты? - PullRequest
7 голосов
/ 26 октября 2010

Рассмотрим следующее ::

Object box = 5;
int @int = (int)box;  // int = 5
int? nullableInt = box as int?; // nullableInt = 5;
StringComparison @enum = (StringComparison)box; // enum = OrdinalIgnoreCase
StringComparison? nullableEnum = box as StringComparison?; // nullableEnum = null.

2 вещи ::

  1. Почему я могу распаковать на StringComparison? Я предполагаю, что это потому, что его базовый тип Int32, но я все еще нахожу его странным.
  2. Почему nullableEnum имеет значение null?

Как я понимаю, единственная допустимая распаковка относится к типу значений в штучной упаковке - к его типу или к обнуляемому типу. Если int может распаковать в Enum, то почему то же самое не относится к значениям Nullable? Точно так же, если бы вместо 5 я поместил в коробку StringComparison.OrdinalIgnoreCase, это было бы, что nullableInt было бы нулевым, но nullableEnum не было бы.

Ответы [ 3 ]

3 голосов
/ 26 октября 2010

Строго говоря, я думаю, что это ошибка в подробности реализации времени выполнения, поскольку спецификация C # говорит:

Распаковка в тип NULLнулевое значение типа nullable-типа, если исходный операнд имеет значение null, или завернутый результат распаковки экземпляра объекта в базовый тип типа nullable-типа в противном случае.

То есть, если распаковывать вStringComparison работает, тогда распаковка на Nullable тоже должна работать.Немного неясно, должны ли оба работать или оба должны потерпеть неудачу.В спецификации сказано, что

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

Вы должны решить, считается ли упакованное целое int упакованным значением типа StringComparison, потому что базовый тип StringComparison - int.Далее в спецификации говорится, что InvalidCastException генерируется, если в поле содержится «несовместимый объект».Int, безусловно, «совместим» со StringComparison, поскольку вы можете безопасно скопировать четыре байта из кучи в переменную StringComparison.

1 голос
/ 26 октября 2010

Когда вы приводите enum или integer к объекту, он по-прежнему содержит информацию о типе. Так что box is StringComparison вернет false. Но разрешено приводить любое перечисление или int к любому перечислению, поэтому работает явное приведение (StringComparison)box. Это особый случай для перечислений. Nullable<T>, с другой стороны, это просто обычный класс, T не обрабатывается каким-либо определенным образом, когда вы применяете или проверяете тип. Вот почему этот код будет выдавать исключение.

        StringComparison? nullableEnum = (StringComparison?)nullableInt;
0 голосов
/ 26 октября 2010

1) Да, базовый тип enum - это int, и поэтому он работает таким образом. Даже больше. Вы можете сделать следующее:

enum MyEnum
{
    One = 1,
    Two = 2,
}

int i = 3;
MyEnum myEnum = (MyEnum)i; // This works without exceptions.

2) Потому что StringComparison? на самом деле Nullable<StringComparison> другого типа. И as оператор только проверяет, является ли объект того же типа, который указан в качестве оператора.

...