массив, содержащий ссылку на вымерший объект - PullRequest
4 голосов
/ 01 июля 2010

Я думал, что если бы массив C # содержал ссылочные типы, он просто содержал бы ссылки на каждый из объектов, однако приведенный ниже код говорит мне об обратном.Похоже, что массив содержит ссылку на объект, который, как я думал, был задан как сборщик мусора.Я чувствую, что мне здесь не хватает чего-то фундаментального.Может кто-нибудь сказать мне, почему ссылка на массив не изменяется при переназначении foo?

    abstract class AbstractBaseClass
    {
        protected int _someProperty;

        public virtual int SomeProperty
        {
            get
            {
                return _someProperty;
            }
            set
            {
                _someProperty = value;
            }
        }
    }

    class DerrivedClass1 : AbstractBaseClass
    {

    }

    class DerrivedClass2 : AbstractBaseClass
    {
        public override int SomeProperty
        {
            get
            {
                return _someProperty + 1;
            }
            set
            {
                _someProperty = value;
            }
        }
    }

    static void Main()
    {
        AbstractBaseClass foo;
        AbstractBaseClass bar;
        AbstractBaseClass[] array = new AbstractBaseClass [1];

        foo = new DerrivedClass1();
        foo.SomeProperty = 99;
        array[0] = foo;
        Console.WriteLine("Value of foo.SomeProperty: " + foo.SomeProperty.ToString());

        bar = new DerrivedClass2();
        bar.SomeProperty = 99;
        Console.WriteLine("Value of bar.SomeProperty: " + bar.SomeProperty.ToString());

        foo = bar;
        Console.WriteLine("Value of foo.SomeProperty after assignment: " + foo.SomeProperty.ToString());

        Console.WriteLine("Value of array[0] after assignment: " + array[0].SomeProperty.ToString());

    }

Ответы [ 7 ]

3 голосов
/ 01 июля 2010

Вы изменили ссылку на переменную foo, а не array[0].

В своем уме вы думаете, что array[0] указывает на foo, где они фактически указывают на одну и ту же область памяти в куче.

Когда вы назначаете bar на foo, вы меняете место, на которое указывает foo. Вы не коснулись array[0], поэтому он по-прежнему указывает на ту же область памяти, на которую он всегда указывал - оригинал foo.

3 голосов
/ 01 июля 2010

Когда вы устанавливаете:

array[0] = foo;

Вы на самом деле делаете копию по значению ссылки на объект, на который указывает foo, и копируете эту ссылку в "array [0]".

Позже, когда вы сделаете:

foo = bar;

Вы делаете то же самое - копируете по значению , ссылку на объект, на который указывает бар, впеременная foo. не влияет на массив [0], так как ссылка изначально была скопирована по значению.Чтобы сделать первый экземпляр DerivedClass1 (исходная ссылка foo) кандидатом в GC, вам необходимо явно установить массив [0] для какой-либо другой ссылки (или ноль).

1 голос
/ 01 июля 2010

foo ссылается только на объект, который хранится в памяти.

array[0] = foo скопирует ссылку на массив, поэтому и массив, и foo теперь указывают на один и тот же объект.

foo = bar скопирует ссылку bar на foo, поэтому и foo, и bar указывают на второй объект. Но массив все равно будет указывать на первый объект, потому что вы не изменили ссылку в массиве.

Вы должны думать об этом как домашний адрес. Если двое из ваших друзей знают ваш старый адрес, но вы только сообщаете другу A свой новый адрес, друг B посетит ваш старый адрес и найдет ваш старый дом. В вашем примере массив является другом B и знает только местоположение первого объекта в памяти.

1 голос
/ 01 июля 2010

Элемент массива хранит ссылку на объект, на который изначально ссылается foo. Элемент массива не привязан к foo напрямую. При изменении объекта, на который ссылается foo, элемент массива не изменяется.

Foo foo = new Foo();
foo.Name = "Andy";
Foo anotherFoo = foo;
foo.Name = "Bart";
Console.WriteLine(anotherFoo.Name); // writes Bart
foo = new Foo();
foo.Name = "Claire";
Console.WriteLine(anotherFoo.Name); // writes Bart

Пока вы изменяете свойства объекта, на который ссылается foo, другие переменные, ссылающиеся на этот же объект, будут "видеть" эти обновления, потому что они смотрят на тот же объект.Однако, когда я говорю foo = new Foo() (или вы говорите foo = bar), вы изменяете foo на ссылку на другой объект.

Ваш элемент массива не знает или не заботится о foo,он знает только об объекте, на который ссылался foo во время присваивания.

1 голос
/ 01 июля 2010

Вы не думаете о назначении ссылок должным образом.array[0] = foo; заставляет ячейку памяти array[0] содержать ссылку на тот же объект, на который ссылалась ячейка памяти foo.Это не заставляет array[0] ссылаться на саму ячейку памяти foo.Таким образом, изменение объекта foo ссылок не влияет на объект array[0] ссылок.

0 голосов
/ 01 июля 2010

Вы создаете новый объект DerivedClass1 и сохраняете его ссылку в foo, затем копируете эту ссылку в массив [0], копируете его, то есть в этот момент у вас есть две ссылки на один и тот же объект.

Когда вы делаете foo = bar;, вы перезаписываете первую копию ссылки из переменной foo, а не самой ссылки, поэтому теперь foo просто указывает на другой объект, тот же, на который указывает bar, но массив [0] все еще указывает к первому, поэтому он не должен собирать мусор, а объект остается неизменным.

0 голосов
/ 01 июля 2010

У вас есть две ссылки на экземпляр DerrivedClass1:

  • Локальная переменная foo, хотя foo перестает быть ссылкой на первый объект, как только вы назначите barк нему
  • элемент массива на array[0].Эта ссылка остается неизменной до конца метода.

Присваивание переменной foo никогда не повлияет на содержимое массива - только изменение array[0] сделает это.

Объект не подходит для сборки мусора, пока все ссылки на него не очищены.Это означает, что объект DerrivedClass1 не будет собираться мусором до тех пор, пока массив не будет собран мусором.

...