Повторный бокс дает разные ссылки?

Я пытаюсь понять этот код:

double b = 3;
object o = b;
Console.WriteLine(o.Equals(3));//false
Console.WriteLine(o.Equals(b));//true
Console.WriteLine( o == (object)b );//false
  1. Каждый новый бокс делает разные ссылки на объект б?
  2. Если 1. верно, почему o.Equals(b) является true?
  3. Если Equals не проверяет ссылки, почему o.Equals(3) является false?

Благодарю.

4 ответа

Решение
  1. Да, каждый раз, когда вы указываете тип значения, создается новый объект. Подробнее о боксе здесь.
  2. Equals проверять равенство значений, а не ссылочное равенство. И то и другое o а также b одинаковы: double со значением 3.0,
  3. 3 вот intне double, а также Equals для разных типов не выполняется никаких преобразований, чтобы сделать их совместимыми, как это обычно делает компилятор. o.Equals(3.0) вернусь true,
double b = 3;

создает новую переменную в стеке со значением 3

object o = b;

создает объект в куче, которая ссылается на то же место b в стеке, так что у вас есть однаи та же переменная с двумя ссылкамиэто бокс

o.Equals(3)

ложь, потому что она создает новую анонимную переменную со значением 3, ане b

o.Equals(b) 

верно, потому что это одна и та же переменная

o == (object)b

ложно, потому что== сравнивает ссылки в памяти, но Equals сравнивает значение самой переменной

Посмотрите, это объясняет все о поведении равных.

Каждый раз, когда предпринимается попытка преобразовать тип значения в ссылочный тип, его необходимо поместить в новый экземпляр объекта. Система не может сделать что-либо еще, не нарушая совместимость. Помимо всего прочего, хотя можно ожидать, что коробочные типы значений будут неизменными (*), ни один из них не является. Каждый тип значения в штучной упаковке дает изменяемый объект. Хотя C# и vb.net не предоставляют какого-либо удобного способа мутировать такие объекты, доверенный и проверяемый код, написанный на C++/CLI, может сделать это легко. Даже если система знала об объекте кучи, который содержит Int32 чье значение в настоящее время 23, утверждение Object foo = 23; придется генерировать новый Int32 объект кучи со значением 23, поскольку у системы не будет возможности узнать, может ли что-то планировать изменить значение этого существующего объекта на 57.

(*) Я бы сказал, что они должны быть; вместо того, чтобы сделать все упакованные объекты изменяемыми, было бы гораздо лучше предоставить средство, с помощью которого типы структур, такие как List<T>.Enumerator можно указать настраиваемое поведение бокса. Я не уверен, есть ли способ исправить это, не нарушая совместимость с существующим кодом.

Другие вопросы по тегам