C # Путать со списком внутри структуры (тип значения против ссылочного типа) - PullRequest
4 голосов
/ 25 июля 2011

Итак, сегодня я обнаружил, что структуры и классы действуют по-разному, когда используются для присваивания переменных в C #. Насколько я понимаю, когда я присваиваю структуру переменной, переменная хранит копию этой структуры, и когда я назначить класс переменной, переменная хранит ссылку на этот экземпляр класса.

В этом случае dad2 содержит копию dad1, поэтому не должно ли что-либо, что я сделать с dad2, не повлиять на dad1? Очевидно, это не тот случай, потому что когда я добавляю сына в dad2, он также добавляет того же сына в dad1.

public struct Dad {
        public string name;
        public List <Son> sons;

        public struct Son {
            public string name;

            public Son (string n) {
                name = n;
            }
        }
    }

    static void Main (string [] args) {
        Dad dad1 = new Dad ();
        dad1.name = "Bob";
        dad1.sons = new List <Dad.Son> {new Dad.Son ("A")};

        Dad dad2 = dad1;
        Debug.WriteLine (dad2.Equals (dad1) + " " + dad1.sons.Count () + " " + dad2.sons.Count ());
        //true 1 1
        dad2.sons.Add ( new Dad.Son ("B"));
        Debug.WriteLine (dad2.Equals (dad1) + " " + dad1.sons.Count () + " " + dad2.sons.Count ());
        //true 2 2
    }

Ответы [ 3 ]

3 голосов
/ 25 июля 2011

да, он создает копию значений внутри структуры - и внутри структуры есть ссылка на список, так что ссылка тоже копируется - это «мелкая копия» ... если список был бы скопирован поверхдля нового объекта это будет "глубокая копия" ... При назначении структуры используется семантика "копирования", которая зависит от семантики копирования каждого элемента ... см. http://msdn.microsoft.com/en-us/library/saxz13w4.aspx

1 голос
/ 06 октября 2011

Думайте о переменных и полях типа класса как об «идентификаторах экземпляров», и все будет ясно.Предположим, что структурное поле «Foo» типа List имеет значение «Instance ID # 95341».Копирование структуры приведет к созданию другой структуры, поле которой «Foo» также содержит «Экземпляр ID # 95341».Вызов Foo.Add для одной такой структуры добавит элемент в список , на который ссылается"Идентификатор экземпляра # 95341".Запрашивая Foo.Count для другой такой структуры, получим счет из списка, на который ссылается «ID экземпляра # 95341», который, естественно, будет тем же списком.

0 голосов
/ 10 июля 2018

Я отвечаю на это

так что, ничего, что я должен сделать для dad2, не повлияет на dad1? "

С вашим кодом любые изменения в

public List <Son> sons;

видно в обоих экземплярах (папа1 и папа2); Однако любое изменение в

public string name;

видно только на измененном объекте

Пример - изменить только имя dad2, а не имя dad1

Dad dad1 = new Dad();
dad1.name = "Bob";
dad1.sons = new List<Dad.Son> { new Dad.Son("A") };

Dad dad2 = dad1;
Console.WriteLine(dad2.Equals(dad1) + " " + dad1.sons.Count() + " " + dad2.sons.Count());
//true 1 1
dad2.sons.Add(new Dad.Son("B"));
Console.WriteLine(dad2.Equals(dad1) + " " + dad1.sons.Count() + " " + dad2.sons.Count());
//true 2 2

dad2.name = "Tom";
Console.WriteLine(dad2.Equals(dad1) + " " + dad1.sons.Count() + " " + dad2.sons.Count());
//False 2 2
...