Зачем .net (все еще) нужен бокс?

Я читал блог Эрика Липперта, особенно по темам о куче, стеке и регистрах, и, насколько я понимаю, решение о размещении переменной в куче или стеке в основном связано со «временем жизни» переменной, т.е. ' или "долгоживущий", и если что-то делается с переменной в стеке, что увеличивает ее время жизни сверх времени жизни функции, в которой она объявлена, она становится кандидатом на "продвижение" кучи через класс-оболочку времени компиляции, как в случай переменных стека, используемых в замыканиях. Итак, вопрос в том, почему компилятор .net (до сих пор) не идентифицирует кандидатов, которым нужен бокс, и выбирает для реализации класс, который, конечно, всегда будет размещаться в куче? И вообще отказаться от бокса?


person Vinay Sharma    schedule 02.05.2014    source источник
comment
Я не вижу, как то, что вы предлагаете, будет улучшением. Более того, это не то, что можно обнаружить во время компиляции для всех случаев.   -  person Brian Rasmussen    schedule 02.05.2014
comment
.. и выберите реализацию класса, - это будет бокс, во всех смыслах и целях.   -  person Henk Holterman    schedule 02.05.2014
comment
Если я могу выразить это по-другому. Почему бы не использовать бокс при работе с замыканиями? Я не пытаюсь что-либо предложить, скорее мне просто любопытно, почему существуют два разных способа работы с двумя, казалось бы, похожими сценариями, т.е. бокс против типов значений в замыканиях. Хотя Брайан указал, что может оказаться невозможным определить, будет ли переменная помещена в коробку или нет, мне все еще не ясно, что это может быть за сценарий.   -  person Vinay Sharma    schedule 02.05.2014
comment
Вы не можете упаковать все экземпляры int просто потому, что вам нужно упаковать несколько из них, и вы не можете не упаковать какие-либо экземпляры int просто потому, что вам нужно упаковать только некоторые из них. Какой у Вас вопрос?   -  person Lasse V. Karlsen    schedule 03.05.2014


Ответы (2)


Я собираюсь ответить на вопрос, который вы задали в своем комментарии, и я думаю, что это тот же вопрос, только сформулированный по-другому, потому что я думаю, что это поможет устранить ваше замешательство.

Мне просто любопытно, почему существуют два разных способа работы с двумя, казалось бы, похожими сценариями, т.е. бокс против типов значений в замыканиях.

Есть две операции, о которых вы говорите, «бокс» и «подъем», и они делают две совершенно разные вещи. Деталь реализации заключается в том, что они делают эти вещи с помощью схожих средств, но решают разные проблемы и предъявляют разные требования.

Цель упаковки состоит в том, чтобы позволить типам значений сохраняться как ссылочные типы и извлекаться позже. Это не имеет ничего общего с областью действия рассматриваемых переменных, и все, что связано с обеспечением безопасности типов. Бокс может происходить полностью в локальной области действия переменной, например:

int i = 1;
object o = i;
int j = (int)o;

Но чаще он используется, когда необходимо передать тип значения параметру, который ожидает ссылочный тип, например:

string.Format("The value is {0}", 10);

string.Format принимает параметр params object[], поэтому каждый тип значения, переданный в метод, заключен в коробку. В системе типов CLR все типы значений наследуются от System.Object, поэтому обработка типа значения как объекта всегда является безопасной операцией. Операция распаковки, с другой стороны, полагается на то, что разработчик распаковывает нужные вещи из нужных коробок, проверка, которая может произойти только во время выполнения, поскольку компилятор не может точно знать, что такое «настоящие» значения. хранящиеся в этих объектах, отсутствуют во время компиляции.

Другая операция, подъем, используется для изменения времени жизни идентификатора по умолчанию, которое обычно вытекает из его лексической области видимости. Эта операция подъема должна выполняться для любых типов данных, значений или ссылочных типов, которые вот-вот покинут область видимости, но должны быть сохранены (например, они были закрыты лямбдой). Это делается не для того, чтобы изменить представление типа данных, а для того, чтобы убедиться, что значения доступны после возврата метода, и предотвратить сборку мусора теперь недоступных эталонных экземпляров.

Обратите внимание, что типы «поднятых» значений не заключены в рамку. Компилятор создает класс для представления всего замыкания, включающего элементы типа значения для любых закрытых идентификаторов типа значения. Эти типы значений никогда не помещаются в object и извлекаются позже, как и ваши собственные поля типов значений.

Вы, кажется, сосредотачиваетесь на том факте, что обе эти операции реализуются путем создания нового экземпляра класса, который «содержит» упакованный или поднятый тип. Но это действительно не должно вас удивлять. Все в .NET осуществляется с помощью объектов. Этот один общий поток не делает эти операции достаточно похожими, чтобы исключить любую из них. Если вы попытаетесь объединить их в одну операцию, вы, скорее всего, получите крайне неэффективную операцию, которая просто постоянно выполняет оба действия, когда это редко требуется.

person Michael Edenfield    schedule 02.05.2014
comment
Спасибо за время. «Эта операция подъема должна быть выполнена для любых типов данных, значений или ссылочных типов, которые вот-вот покинут область действия, но должны быть сохранены...» очистил это для меня. Теперь это кажется очевидным, но чертовски смущало меня. - person Vinay Sharma; 03.05.2014

В приведенном вами примере закрытие обрабатывается во время компиляции, а упаковка происходит во время выполнения, но в обоих примерах вы продвигаете время жизни переменной.

person user3597548    schedule 02.05.2014