В этой статье мы коротко пройдемся по малоизвестным особенностям boxing/unboxing.
Предыдущая статья о foreach
Предыдущая статья об Array
Типичный вопрос на собеседовании об упаковке и распаковке выглядит следующим образом — «Что будет при запуске данного кода, и если он не будет работать то как его исправить?».
Тестовый код:
object box = (int)42;
long unbox = (long)box;
Ответ может быть следующий — «При распаковке первый оператор является не приведением типов а распаковкой типа, соответственно он должен соответствовать типу значения находящегося в запакованном виде.».
Правильный ответ:
object box = (int)42;
long unbox = (long)(int)box;
Обычно это считается правильным ответом, но это не совсем так…
Unboxing и Enum
Представьте себе удивление человека, когда вы ему напишете другой правильный вариант.
Второй правильный ответ:
public enum EnumType { None }
...
object box = (int)42;
long unbox = (long)(EnumType)box;
Напомню, enum не является фундаментальным типом и не наследует его, он является структурой содержащей фундаментальный тип (базовый). Это говорит о том что в .NET есть явная поддержка такой распаковки. Так же легко проверить что распаковка не использует операторы явного и неявного преобразования и интерфейс IConvertible и свой тип не получится развернуть из чужого типа.
При распаковке enum'а используется его базовый тип и следующая распаковка не будет работать.
Неправильный вариант:
public enum EnumType : short { None }
...
object box = (int)42;
long unbox = (long)(EnumType)box;
Распаковка для enum'ов ослаблена предельно.
Распаковываем int из enum'а:
public enum EnumType { None }
...
object box = EnumType.None;
long unbox = (long)(int)box;
Распаковываем один enum из другого:
public enum EnumType { None }
public enum EnumType2 { None }
...
object box = EnumType.None;
long unbox = (long)(EnumType2)box;
Unboxing и Nullable
Распаковка поддерживает и Nullable типы, что кажется более логичным.
Распаковка Nullable типа из обычного:
object box = (int)42;
long unbox = (long)(int?)box;
Распаковка обычного типа из Nullable:
object box = (int?)42;
long unbox = (long)(int)box;
Напомню что Nullable это структура с одним обобщенным типом значения и предназначена для хранения данных и флага присутствия данных. Это говорит о том что в C# есть явная поддержка распаковки Nullable типов. В новых версиях C# для этой структуры появился alias "?".
Nullable:
public struct Nullable<T> where T : struct
{
public bool HasValue { get; }
public T Value { get; }
}
Равнозначные записи:
Nullable<int> value;
int? value;
Всем спасибо за внимание!
Автор: mynameco