Рассмотрим:
int a = 42;
// Reference equality on two boxed ints with the same value
Console.WriteLine( (object)a == (object)a ); // False
// Same thing - listed only for clarity
Console.WriteLine(ReferenceEquals(a, a)); // False
Ясно, что каждая инструкция по боксу выделяет отдельный экземпляр вложенного в квадрат Int32
, поэтому ссылочное равенство между ними не выполняется. Эта страница указывает, что это указано поведение:
Команда box преобразует 'raw' (unboxed) в объект ссылка (тип O). Это выполненный с помощью создания нового объектаи копирование данных из значения введите в новый выделенный объект.
Но почему это должно быть так?
Есть ли веская причина, по которой CLR не хочет хранить "кеш" в коробке Int32
s или даже более сильные общие значения для всех примитивных типов значений (которые все неизменяемы)? Я знаю, что Java имеет что-то вроде этого.
В дни отсутствия дженериков, не помогло бы это с уменьшением требований к памяти, а также рабочей нагрузкой GC для большого ArrayList
, состоящего в основном из небольших целых чисел? Я также уверен, что существует несколько современных .NET-приложений, которые используют дженерики, но по какой-либо причине (отражение, назначения интерфейсов и т.д.) Запускают большие бокс-распределения, которые могут быть значительно уменьшены (как представляется) простая оптимизация.
И какая причина? Некоторое влияние на производительность, которое я не рассматривал (я сомневаюсь, что тестирование того, что элемент находится в кеше и т.д., Приведет к потере чистой производительности, но что я знаю)? Проблемы с внедрением? Проблемы с небезопасным кодом? Разрыв обратной совместимости (я не могу придумать какой-либо веской причины, почему хорошо написанная программа должна опираться на существующее поведение)? Или что-то другое?
EDIT. То, что я действительно предлагал, было статическим кешем "обычных" примитивов, как и то, что делает Java. Для примера реализации см. Ответ Джона Скита. Я понимаю, что выполнение этого для произвольных, возможно изменяемых, типов значений или динамически "memoizing" экземпляров во время выполнения - это совсем другое дело.
EDIT: Изменено название для ясности.