Повторный бокс дает разные ссылки?
Я пытаюсь понять этот код:
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. верно, почему
o.Equals(b)
являетсяtrue
? - Если
Equals
не проверяет ссылки, почемуo.Equals(3)
являетсяfalse
?
Благодарю.
4 ответа
- Да, каждый раз, когда вы указываете тип значения, создается новый объект. Подробнее о боксе здесь.
Equals
проверять равенство значений, а не ссылочное равенство. И то и другоеo
а такжеb
одинаковы:double
со значением3.0
,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
можно указать настраиваемое поведение бокса. Я не уверен, есть ли способ исправить это, не нарушая совместимость с существующим кодом.