Pull to refresh

Интересные моменты в C# (boxing unboxing)

Reading time 2 min
Views 71K
В этой статье мы коротко пройдемся по малоизвестным особенностям 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;

Всем спасибо за внимание!
Tags:
Hubs:
+18
Comments 10
Comments Comments 10

Articles