Search code examples
c#variable-assignmentreference-type

c# - reference type referencing another reference type


Note: This applies to both List and ArrayList

Take a look at the following simple code:

class Creature
{
    public string Name;
}

class Game
{
    // This is a reference type
    public Creature CurrentCreature;
}

class Program
{
   static void Main(string[] args)
   {
        // First, we'll create 2 objects and let the 
        // reference type "CurrentCreature" points to one of them
        Creature dragon = new Creature();
        dragon.Name = "Dragon";        

        Creature Unicorn = new Creature();
        dragon.Name = "Unicorn";

        Game game = new Game();
        game.CurrentCreature = dragon;

        // Now we'll create a list which will contain
        // the reference type "CurrentCreature"
        List<Creature> list = new List<Creature>();                
        list.Add(game.CurrentCreature);

        foreach (Creature c in list)
        {
            Console.WriteLine(c.Name);    // Output is "Dragon"
        }

        // Now, we'll let "CurrentCreature" point to a different object
        game.CurrentCreature = unicorn;

        // The reference in the list still pointing to the original object!!!
        foreach (Creature c in list)
        {
            Console.WriteLine(c.Name);   // Output is "Dragon"!!! 
        }

        Console.ReadLine();
   }
}

I checked how a list adds an item and there is no instantiation of a new object. This is List.Add method (using Reflector tool)

   public void Add(T item)
        {
            if (this._size == this._items.Length)
            {
                this.EnsureCapacity(this._size + 1);
            }
            this._items[this._size++] = item;   // No instantiation
            this._version++;
        }

So, why is this happenning? The element in the list should be a reference to the object pointed to by "CurrentCreature" or is it not? Isn't it similar to the following code if we remove the list?:

class A
{
    public B X;
}
class B
{
    public string Name;
}
....

A a = new A();
B b1 = new B(); b1.Name = "b1";
B b2 = new B(); b2.Name = "b2";
a.X = b1;

Console.WriteLine(a.X.Name); // output: b1
b1 = b2;
Console.WriteLine(a.X.Name); // output: b1

Solution

  • When you do

    game.CurrentCreature = unicorn;
    

    You overwrite the pointer in game.CurrentCreature with one to the unicorn object. The array still has a pointer to the dragon object. It shouldn't be changed, this is how pointers work.

    Edit:

    A little explanation of what happens with the pointers:

    First you created 2 objects

    Creature dragon = new Creature();
    dragon.Name = "Dragon";        
    
    Creature Unicorn = new Creature();
    dragon.Name = "Unicorn";
    

    This made dragon have a pointer to your dragon object, and unicorn have a pointer to your unicorn object.

    Then you set the pointer of game.CurrentCreature to dragon's pointer.

    game.CurrentCreature = dragon;
    

    Then you add a pointer to dragon, the current creature, to the list

    List<Creature> list = new List<Creature>();                
    list.Add(game.CurrentCreature);
    

    Then you replace the pointer in game.CurrentCreature(was dragon) with a pointer to the unicorn object.

    game.CurrentCreature = unicorn;
    

    This will in no way affect the pointer held in the dragon object.

    Cheers,