views:

60

answers:

7

I thought that if a C# array held reference types it would simply hold references to each of the objects, however the code below tells me otherwise. It appears as if the array is holding a reference to an object of which I thought was set to be garbage collected. I feel like i'm missing something fundamental here. Can anyone tell me why the array reference does not change when foo is reassigned?

    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());

    }
+1  A: 

You are not thinking about reference assignment properly. array[0] = foo; causes the memory location array[0] to hold a reference to the same object that the memory location foo was referencing. It does not cause array[0] to reference the memory location foo itself. Therefore, changing which object foo references does not affect which object array[0] references.

Jeffrey L Whitledge
A: 

You have two references to the DerrivedClass1 instance:

  • The local foo variable, although foo ceases being a reference to the first object as soon as you assign bar to it
  • The array item at array[0]. This reference remains intact until the end of the method.

The assignment to the foo variable will never affect the contents of the array -- only making a change to array[0] will do that.

The object isn't eligible for garbage collection until all the references to it are cleared. This means that the DerrivedClass1 object won't be garbage collected before the array is garbage collected.

Tim Robinson
+3  A: 

When you set:

array[0] = foo;

You're actually doing a by-value copy of the reference to the object pointed to by foo, and copying that reference into "array[0]".

Later, when you do:

foo = bar;

You're doing the same thing - copying, by value, the reference to the object pointed to by bar, into the variable foo. This has no effect on array[0], since the reference was copied by value originally. In order to make the first DerivedClass1 instance (foo's original reference) a candidate for GC, you need to explicitly set array[0] to some other reference (or null).

Reed Copsey
+1  A: 

The array element is storing the reference to the object that is initially referenced by foo. The array element is not tied to foo directly. When you modify what object foo references, the array element is unaffected.

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

While you're modifying the properties of the object referenced by foo, other variables referencing that same object will "see" those updates, because they're looking at the same object. However, when I say foo = new Foo() (or you say foo = bar), you're changing foo to reference another object.

Your array element does not know or care about foo, it only knows about the object foo was referencing at the time of the assignment.

Anthony Pegram
A: 

You create a new DerivedClass1 object and store its reference in foo, then you copy that reference to array[0], you copy it, that is, at that point you have two references to the same object.

When you do foo = bar; you overwrite the first copy of the reference from the foo variable, not the reference itself, so now foo simply points to another object, the same that bar is pointing, but array[0] still points to the first one, so it should not be garbage collected, and the object is unchanged.

Francisco Soto
+3  A: 

You changed the reference of the variable foo, not of array[0].

In your mind, you are thinking that array[0] points to foo, where they actually both point to the same memory location within the heap.

When you assign bar to foo, you are changing the place to which foo points. You haven't touched array[0], so it still points to the same memory location it always pointed to--the original foo.

Will
Also, this has nothing to do with garbage collection. I'd suggest grabbing a copy of CLR Via C# by Jeffrey Richter. Great book for someone at your level.
Will
@Will Thanks for the book, I'm reading it now.
Joel B
+1  A: 

foo only references the object, which is stored in memory.

array[0] = foo will copy the reference to the array, so both the array and foo now point to the same object.

foo = bar will copy the bar reference to foo, so both foo and bar point to the second object. But the array will still point to the first object, because you haven't changed the reference in the array.

You should think of it as a home address. If two of your friends know your old address, but you only tell friend A your new address, friend B will visit your old address and find your old house. In your example, the array is friend B and only knows the in-memory location of the first object.

Niels van der Rest