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

В чем разница между поверхностным и глубоким копированием?

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

Это зависит от ситуации и от какого клона вы должны использовать в своем проекте. Далее мы увидим несколько примеров на C#, касающихся обсуждаемой темы.

Как создавать поверхностные и глубокие копии

Для этого я создал консольное приложение .NET.
Исходный код можно найти здесь.

Настройка программы

Person.cs - Чертеж объекта, который мы будем клонировать позже.

Address.cs - Данные для класса Person.

Program.cs — Где будет происходить клонирование, содержит Main, точку входа приложения.

После создания классов, переопределения унаследованной функции ToString() и запуска программы вывод:

Как мы видим, объект person размещен в памяти правильно.

Создать неглубокий клон

Чтобы создать неглубокий клон, мы можем просто добавить следующие строки в метод Main:

или реализовать метод Clone() в Person и добавить в метод Main следующие строки:

Результат будет одинаковым при использовании двух методов:

Как видите, объект person и shallowClone указывают на один и тот же адрес памяти. Это означает, что если shallowClone изменится, человек тоже изменится.

Создать глубокий клон

Для создания глубокого клона нам нужно изменить метод Clone() в Person и добавить следующие строки в метод Main:

Вывод после повторного запуска:

Как мы видим, новый объект deepClone указывает на другой адрес памяти, но атрибут Address трех объектов по-прежнему имеет один и тот же адрес в памяти.

Это означает, что изменение FirstName, LastNameили Age в объекте deepClone не влияет на два других объекта. Но если мы изменим Address в deepClone, это также повлияет на исходный объект person и smallClone.

Чтобы решить эту проблему, нам нужно изменить класс Address, чтобы реализовать также ICloneable, а затем добавить метод Clone().

и измените метод Clone() в Person.

Вывод после исправления:

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

Заключение

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

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

Не стесняйтесь обращаться ко мне в любое время — я буду рада обменяться новыми идеями и вдохновить друг друга!