В чем разница между методом клонирования и непосредственным назначением экземпляра другому - PullRequest
3 голосов
/ 15 декабря 2011

Я хочу знать, если у меня есть класс с именем Test, какая разница ниже

Test test = new Test();
Test newTest = test;
Test newTest2 = test.Clone();

В чем разница между newTest и newTest2? Кто-нибудь может помочь? Заранее спасибо!

Ответы [ 5 ]

2 голосов
/ 15 декабря 2011

Когда вы присваиваете экземпляр, если Test является классом, вы фактически копируете ссылку, но test и newTest оба будут указывать на один и тот же экземпляр в памяти.

Это означает, что обе переменные указывают на один и тот же объект:

Test test = new Test();
test.Foo = 24;
Test newTest = test;
newTest.Foo = 42;
Console.WriteLine(test.Foo); // Prints 42!

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

Обратите внимание, что если test является struct (тип значения), то прямое присвоение фактически является полной (мелкой) копией объекта по значению.

1 голос
/ 18 декабря 2011

Чтобы понять различие, нужно сначала понять, что такое ссылка на объект. Поскольку термин «ссылка» используется для обозначения ряда различных понятий, мне нравится термин «Идентификатор объекта». Чтобы использовать автомобильную аналогию, идентификатором объекта является лист бумаги с VIN-кодом автомобиля. Если вы передадите в магазин краски лист бумаги с надписью «VIN ZX357» и попросите магазин покрасить его в синий цвет, магазин не покрасит листок бумаги в синий, а скорее найдет автомобиль с этим номером VIN. и покрасить эту машину в синий.

Если у вас есть переменная Wuzzle типа Car (которая является ссылочным типом), которая содержит VIN ZX357, и другая переменная Fuzzle, и одна говорит Fuzzle = Wuzzle, тогда Fuzzle будет - like Wuzzle удерживайте "VIN ZX357". Там еще будет одна машина. У одного будут только две бумажки, каждая из которых содержит один и тот же VIN и, следовательно, относится к одной и той же машине. Заявление типа Wuzzle.Color=Purple приведет к тому, что автомобиль с VIN ZX357 будет окрашен в фиолетовый цвет Запрос на проверку Fuzzle.Color будет смотреть на автомобиль ZX357 и сообщать, что он фиолетовый.

Если вместо того, чтобы сказать Fuzzle = Wuzzle, кто-то сказал Fuzzle = (Car)(Wuzzle.Clone()), эффект будет состоять в том, чтобы создать новый автомобиль, который будет похож на VIN ZX357, за исключением того, что у него будет другой номер VIN (например, QL793) и * 1015. * будет содержать новый VIN, а не 3941QXY5). Сказав Wuzzle.Color = Orange, можно покрасить автомобиль 3941QXY5 в оранжевый цвет, но это не повлияет на автомобиль QL793.

Переменные типа интерфейса обрабатываются так же, как и любой другой ссылочный тип. Можно заменить IColorizable на Car, и поведение будет точно таким же.

Важно отметить, что ICloneable не очень хороший интерфейс; гораздо лучший интерфейс - ICloneable<T>, который возвращает объект типа T. У этого интерфейса есть два больших преимущества:

  1. С ICloneable необходимо типизировать тип возвращаемого значения к типу объекта, который вы хотите. Это немного некрасиво. ICloneable<T> устраняет это требование.
  2. С ICloneable может быть некоторая неоднозначность относительно того, какие ссылки на объекты внутри объекта должны быть скопированы в клон как есть, а какие должны быть клонированы сами. Неоднозначность не так плоха, как это делают некоторые люди, но обобщенный ICloneable<T> может сделать ее немного понятнее. Например, если у кого-то есть объект CloneableSortedList<T>, то вызов ICloneable<CloneableSortedList<T>.Clone() в этом списке должен вернуть новый CloneableSortedList, который содержит те же ссылки на тип T, что и исходный. Напротив, если у вас есть CloneableSortedUserList, вызов ICloneable<CloneableSortedUserList> должен вернуть новый CloneableSortedUserList, который будет рассматривать атрибуты пользователей, а не ссылки на объекты пользователя, как значения (таким образом, копируя их, если они изменчивы).
1 голос
/ 15 декабря 2011

Назначение копирует только ссылку , а не сам объект.

Если ваш класс реализует IClonable.Clone, его можно записать для выполнения операции глубокое копирование , то есть для возврата вновь выделенного объекта того же типа, полей из которых копии оригинала. Это интересный вопрос, что делать, когда поле имеет ссылочный тип: скопировать ссылку или выполнить глубокое копирование ссылочного объекта? Например, Object.MemberwiseClone копирует только ссылку (это называется мелкая копия ), но если вы решите внедрить IClonable.Clone, то вы можете решай сам.

0 голосов
/ 15 декабря 2011

Новый тест фактически указывает на тот же объект в памяти, что и тест, поэтому изменение newTest меняет тест.newTest2 на самом деле является копией теста.

0 голосов
/ 15 декабря 2011
Test newTest = test;

Поскольку Test является ссылочным типом (классом), newTest теперь ссылается на тот же объект, что и test. Если вы измените объект test ссылки, это будет отражено в newTest, так как они оба ссылаются на один и тот же объект.

Test newTest2 = test.Clone();

Если Clone() возвращает новый экземпляр и делает глубокое копирование (это действительно зависит от вашей реализации), newTest2 ссылается на совершенно отдельный объект, любые изменения в test выиграны не влияет на это.

...