Важно обращать внимание на то, работают ли клонированные или скопированные объекты должным образом, то есть на разницу между поверхностным и глубоким копированием.
В чем разница между поверхностным и глубоким копированием?
Глубокое копирование копирует клонированный объект и все объекты, на которые ссылается объект, рекурсивно, пока не будут скопированы все объекты в объекте. Поверхностная копия может ничего не делать или быть частью настоящего глубокого клона.
Это зависит от ситуации и от какого клона вы должны использовать в своем проекте. Далее мы увидим несколько примеров на 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
, я написал в другой статье здесь.
Привет, ребята, меня зовут Роланд, и я здесь, чтобы поделиться со всеми вами своей страстью к разработке, компьютерной инженерии, управлению проектами, личному развитию, хобби и всему, что между ними.
Не стесняйтесь обращаться ко мне в любое время — я буду рада обменяться новыми идеями и вдохновить друг друга!