c # - ссылочный тип, ссылающийся на другой ссылочный тип - PullRequest
0 голосов
/ 19 декабря 2010

Примечание. Это относится как к списку, так и к списку массивов

.

Взгляните на следующий простой код:

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

Я проверил, как список добавляет элемент, и нет создания экземпляра нового объекта. Это метод List.Add (с помощью инструмента Reflector)

   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++;
        }

Итак, почему это происходит? Элемент в списке должен быть ссылкой на объект, на который указывает CurrentCreature, или нет? Разве это не похоже на следующий код, если мы удалим список?

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

Ответы [ 3 ]

2 голосов
/ 19 декабря 2010

Когда вы делаете

game.CurrentCreature = unicorn;

Вы перезаписываете указатель в game.CurrentCreature одним указателем на объект единорога. Массив все еще имеет указатель на объект дракона. Это не должно быть изменено, так работают указатели.

Edit:

Небольшое объяснение того, что происходит с указателями:

Сначала вы создали 2 объекта

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

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

У этого созданного дракона есть указатель на ваш объект дракона, а у единорога есть указатель на ваш объект единорога.

Затем вы устанавливаете указатель игры. Текущее существо - указатель дракона.

game.CurrentCreature = dragon;

Затем вы добавляете указатель на дракона, текущее существо, в список

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

Затем вы заменяете указатель в game.CurrentCreature (был драконом) указателем на объект единорога.

game.CurrentCreature = unicorn;

Это никак не повлияет на указатель, удерживаемый в объекте дракона.

Приветствия

1 голос
/ 19 декабря 2010

Типы ссылок не просто меняются.

Вы добавляете существо в список, а не в игру. Затем вы меняете ссылку на игру, чтобы использовать существо-анотер; но существо, на которое есть ссылка в списке, остается тем же самым, поэтому оно снова выдает тот же результат.

0 голосов
/ 19 декабря 2010

Ссылка копируется в список, а не объект. После list.Add(myobject); вы получите две ссылки (которые ссылаются на один и тот же объект): myobject и те, что есть в списке.

...