Когда копируется значение / объект C # и когда копируется его ссылка? - PullRequest
61 голосов
/ 03 декабря 2010

Я снова и снова сталкиваюсь с одной и той же проблемой, когда копируется объект, на который я хочу сослаться, или на который ссылается объект, на который я хочу скопировать.Это происходит, когда я использую оператор =.

Например, если я отправляю объект в другую форму, например:

SomeForm myForm = new SomeForm();
SomeObject myObject = new SomeObject();
myForm.formObject = myObject;

..., а затем изменяю объект в формеисходный объект не изменяется.Это как если бы объект был скопирован и на него не ссылались.Тем не менее, когда я делаю это:

SomeObject myObject = new SomeObject();
SomeObject anotherObject = new SomeObject();
anotherObject = myObject;

... и затем изменяю anotherObject, myObject также модифицируется.

Самый отягчающий случай, когда я пытаюсь клонироватьодин из моих определенных объектов:

public class SomeObject
{
    double value1, value2;

    //default constructor here

    public SomeObject(val1, val2)
    {
        value1 = val1;
        value2 = val2;
    }

    public void Clone(SomeObject thingToCopy)
    {
        this.value1 = thingToCopy.value1;
        this.value2 = thingToCopy.value2;
    }
}

, когда я делаю это ...

SomeObject obj1 = new SomeObject(1, 2);
SomeObject obj2 = new SomeObject();
obj2.Clone(obj1);

... obj1 ссылается, и любые изменения obj2 изменяют obj1.

Системные объекты, такие как int, double, string и т. Д., По-видимому, всегда копируются, за исключением случая с описанным выше методом клонирования.

Мой вопрос заключается в том, чтобы не учитывать использованиеключевое слово ref в функциях, когда объект копируется и когда на объект ссылаются в каждом конкретном случае (например, при переходе к функциям, при установке в качестве других объектов (как в первых двух примерах выше), при копированиипеременные-члены, такие как третий пример и т. д.)?

Ответы [ 3 ]

45 голосов
/ 03 декабря 2010

Трудно ответить на этот вопрос точно, не тратя много времени на тщательный подбор слов.

Я сделал это в нескольких статьях, которые могут оказаться полезными:

ЭтоНельзя сказать, что статьи идеальны, конечно - далеко не так - но я старался быть настолько ясным, насколько смог.

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

Чтобы посмотреть на ваши конкретные примеры:

SomeForm myForm = new SomeForm();
SomeObject myObject = new SomeObject();
myForm.formObject = myObject;

Это означает, что myForm.formObject и myObject относятся к одному и тому же экземпляру SomeObject - как два человека, имеющие отдельные листы бумаги, на каждом из которых написан один и тот же адрес.Если вы перейдете по адресу на одном листе бумаги и раскрасите дом в красный цвет, а затем перейдете по адресу на втором листе бумаги, вы увидите красный дом.

Непонятно, что вы подразумеваете под«а затем измените объект в форме», потому что предоставленный вами тип является неизменным.Нет способа изменить сам объект.Вы можете изменить myForm.formObject так, чтобы он ссылался на другой экземпляр SomeObject, но это все равно, что вычеркнуть адрес на одном листе бумаги и вместо этого записать на нем другой адрес.Это не изменит того, что написано на другом листе бумаги.

Если бы вы могли предоставить короткую, но завершенную программу, поведение которой вы не понимаете (в идеале консольное приложение, простоделайте вещи короче и проще) было бы легче говорить о вещах в конкретных терминах.

6 голосов
/ 03 декабря 2010

Привет, Майк Все объекты, производные от ValueType, такие как struct или другие примитивные типы, являются типами значений. Это означает, что они копируются всякий раз, когда вы присваиваете их переменной или передаете в качестве параметра метода. Другие типы являются ссылочными типами, это означает, что, когда вы назначаете ссылочный тип переменной, ей присваивается не ее значение, а ее адрес в пространстве памяти. Также следует отметить, что вы можете передать тип значения в качестве ссылки, используя ключевое слово ref. Вот синтаксис

public void MyMethod(ref int a) { a = 25 }
int i = 20;
MyMethod(ref i); //Now i get's updated to 25.

Надеюсь, это поможет:)

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

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

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

Рассмотрите возможность использования интерфейса IClonable , хотя это не лучшее решение imho.

...