Я читал блог Эрика Липперта, особенно по темам о куче, стеке и регистрах, и, насколько я понимаю, решение о размещении переменной в куче или стеке в основном связано со «временем жизни» переменной, т.е. ' или "долгоживущий", и если что-то делается с переменной в стеке, что увеличивает ее время жизни сверх времени жизни функции, в которой она объявлена, она становится кандидатом на "продвижение" кучи через класс-оболочку времени компиляции, как в случай переменных стека, используемых в замыканиях. Итак, вопрос в том, почему компилятор .net (до сих пор) не идентифицирует кандидатов, которым нужен бокс, и выбирает для реализации класс, который, конечно, всегда будет размещаться в куче? И вообще отказаться от бокса?
Зачем .net (все еще) нужен бокс?
Ответы (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 осуществляется с помощью объектов. Этот один общий поток не делает эти операции достаточно похожими, чтобы исключить любую из них. Если вы попытаетесь объединить их в одну операцию, вы, скорее всего, получите крайне неэффективную операцию, которая просто постоянно выполняет оба действия, когда это редко требуется.
В приведенном вами примере закрытие обрабатывается во время компиляции, а упаковка происходит во время выполнения, но в обоих примерах вы продвигаете время жизни переменной.
int
просто потому, что вам нужно упаковать несколько из них, и вы не можете не упаковать какие-либо экземплярыint
просто потому, что вам нужно упаковать только некоторые из них. Какой у Вас вопрос? - person Lasse V. Karlsen   schedule 03.05.2014