Обновить

Комментарии 3

у вас в проде нашёлся самый неожиданный боксинг

Самый неожиданный боксинг был по поведению для nullable-типов в современном C#. Так приведение nullable-типа к object при боксинге меняется тип. Например, при приведении Int32? varialble к object боксинг произойдёт только в том случае, если variable был не null. Если был null, то боксинга не будет, просто переменной типа object присвоится null и сведения о изначальном типе потеряются и потом при анбоксинге можно будет привести это значение хоть к Boolean?.

Как только struct присваивается переменной интерфейсного типа, он боксится — ведь интерфейс ссылочный. Вызов s.Area() идёт уже по упакованной копии. Если вы держите Circle в локальной переменной конкретного типа и вызываете Area() напрямую — боксинга нет. Грабли вылезают, когда struct “прячут” за интерфейс ради полиморфизма.

Лечение: generic-ограничение where T : struct, IShape вместо переменной интерфейса — JIT специализирует код по value-типу и вызывает метод без упаковки.

Ссылочность вообще не причем. Структуры прекрасно передаются по ссылке без всяких аллокаций. Проблема в том что каждая передаваемая переменная должна иметь фиксированный заранее известный размер. Если переменная интерфейсного типа то размер фактически передаваемых данных может быть любым до 0 и далее. Не может быть переменной или параметра, размер которого никто не знает при исполнении. В отличии от ссылки размер которой всегда фиксированный. Боксинг это способ впихнуть невпихуемое.

Когда мы пишем ограничение where T : struct, IShape то это совсем другая история, так как это скрывает вызов отдельной предварительно сгенерированной функции для каждого используемого типа. У каждой функции будет свой параметр фиксированного размера.

Боксинг, который уже НЕ боксит: чему научился рантайм

Generic-методы со struct-аргументом не боксят сам аргумент. EqualityComparer<T>.DefaultList<T>Dictionary<TKey,TValue> специализируются по value-типу: JIT генерирует отдельный нативный код на каждый struct-аргумент, и упаковки value→object там нет (при условии корректного IEquatable<T> — см. пункт 3).

Что значит уже? В C# изначально мономорфизация параметров типов что значит что любой вариант типа с параметром мономорфизируеться в отдельный тип, там нечему бокситься и незачем. Другими словами, не было никакого List<int> всегда был List_int.

Боксинг это способ впихнуть невпихуемое.

Любопытная интерпретация, но, боюсь, неверная.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации