Равенство объектов в .NET - PullRequest
3 голосов
/ 22 января 2010

Я чувствую себя довольно невежественным, спрашивая это, но сможет ли кто-нибудь объяснить мне, почему это происходит?

class MyClass{ public int i {get; set; } }
class Program
{
    static void Main(string[] args)
    {
        MyClass a = new MyClass();
        MyClass b = new MyClass();

                b.i = 2;
        a = b;
        a.i = 1;

        Console.Write(b.i + "\n"); //Outputs 1
    }
}

Это имеет смысл для меня, если бы я использовал указатели и все такое замечательное, но у меня сложилось впечатление, что в C # этот b останется независимым от "a".

Я просто использую ужасно плохую практику? Может быть, кто-то может указать мне на то, что объясняет, почему это так в C #?

Спасибо.

Ответы [ 6 ]

10 голосов
/ 22 января 2010

Вы перепутали эту строку:

a = b;

Вы ожидали, что b будет скопировано в a по значению, но на самом деле все, что происходит, - это присвоение ссылки от b до a.

.Net делит мир на две категории: ссылочные типы и типы значений (есть также типы делегатов и пара других, но это другая история). Любой определяемый вами класс является ссылочным типом, и о ссылочных типах следует помнить несколько важных моментов:

  • Нет встроенного способа сделать глубокое копирование
  • Будьте внимательны, проверяя равенство. == предназначен для ссылочного равенства (переменные ссылаются на один и тот же объект *), в то время как .Equals() предназначен для равенства значений, и вам может потребоваться переопределить .Equals () (и GetHashCode ()) для ваш тип, чтобы получить это право.
  • присваивание просто копирует ссылку (это та часть, которая вас поразила)
4 голосов
/ 22 января 2010

Вы используете указатели после моды. Объект ссылается по ссылке, если только он не происходит от ValueType .

So

a = b;

Устанавливает ссылку a, равную ссылке b.

2 голосов
/ 22 января 2010

Что вам нужно понять об этом сценарии, так это то, что на самом деле есть 4 объекта интереса.

  1. Экземпляр №1 MyClass
  2. Экземпляр # 2 MyClass
  3. MyClass Reference a
  4. Справочник по MyClass b

Первоначально Ссылка a ссылается на экземпляр № 1, а ссылка b ссылается на экземпляр № 2. Это до тех пор, пока вы не выполните строку a=b;. После этой строки и ссылка a, и ссылка b указывают на экземпляр # 1. Поэтому, когда вы вызываете b.i, вы на самом деле спрашиваете экземпляр № 1, какое значение имеет i Не экземпляр № 2.

1 голос
/ 22 января 2010

Отсутствие указателей - это не то же самое, что отсутствие ссылок на объекты. В вашем случае «a» - это ссылка на конкретный объект типа MyClass, а также «b». Когда вы делаете «a = b», вы копируете ссылку, а не объект, поэтому «a» указывает на тот же объект, что и «b».

0 голосов
/ 21 сентября 2017

Каждый класс в .NET является ссылочным типом. Это означает, что когда вы создаете новый экземпляр, он указывает на ссылку в памяти и не удерживает ее значение.

В вашем случае, когда вы используете = operator (присваивание), вы просто ассоциируете указатель объекта a с указателем объекта b. После этой операции каждое взаимодействие на объекте будет отражаться на других, потому что они просто указывают на одно и то же.

Если вам нужно продублировать объект, вы должны написать код самостоятельно. Но это другая история.

0 голосов
/ 22 января 2010

a и b являются ссылками, поэтому после строки a = b a ссылается на тот же объект, что и b (а объект, на который изначально указывал a, более недоступен). Поэтому, когда вы устанавливаете a.i, вы также обновляете объект, на который ссылается b, отсюда и изменение.

...