Присвоение переменной структуры, содержащей экземпляр класса, другой переменной - PullRequest
2 голосов
/ 27 июня 2011

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

enter image description here

using System;

namespace ReferenceInValue
{
    class Inner
    {
        public int data;
        public Inner(int data) { this.data = data; }
    }

    struct Outer
    {
        public Inner inner;
        public Outer(int data) { this.inner = new Inner(data); }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Outer p1 = new Outer(1);
            Outer p2 = p1;
            Console.WriteLine("p1:{0}, p2:{1}", p1.inner.data, p2.inner.data);


            p1.inner.data = 2;
            Console.WriteLine("p1:{0}, p2:{1}", p1.inner.data, p2.inner.data);


            p2.inner.data = 3;
            Console.WriteLine("p1:{0}, p2:{1}", p1.inner.data, p2.inner.data);

            Console.ReadKey();
        }
    }
}

Ответы [ 3 ]

4 голосов
/ 27 июня 2011

Вы ответили на свой вопрос в теме.

Ваша структура содержит ссылку, когда структура копируется, она копируется как кусок памяти, включая ссылку (а не объект, на который ссылается), так же, как если бы ссылка была целым числом или другим примитивом.

Копирование структуры не вызывает клонирование.

Фактически, размещение ссылки в структуре - плохая идея, и ее следует избегать. Исключением из этого являются неизменяемые ссылочные объекты (например, строки), которые «безопасно» размещать в структурах, поскольку они не могут быть изменены, однако вы все равно потеряете локальность в памяти.

Помните, что типы значений хранятся локально в области их определения, ссылочные типы всегда хранятся в куче, а ссылки хранятся локально в области их определения.

2 голосов
/ 27 июня 2011

В добавление к тому, что сказали другие: если вам нужно убедить себя, что p1.inner и p2.inner действительно указывают на один и тот же экземпляр класса, вы можете запустить код следующим образом:

Console.WriteLine("ReferenceEquals:{0}", object.ReferenceEquals(p1.inner, p2.inner));

Если вы запустите это в любое время после строки «Outer p2 = p1;», она всегда будет писать: «ReferenceEquals: True».

0 голосов
/ 27 июня 2011

P1 и P2 оба указывают на один объект типа Inner ... Вот почему значения одинаковы ...


struct Outer
{
   public Inner inner;
   public Outer(int data) { this.inner = new Inner(data); }

   public Clone() { return new Outer(this.inner.data); }
}

Теперь попробуйте использовать код так:


...
 p2 = p1.Clone();
...