Клонування - це створення копії об'єкту. Копія об'єкту називається клоном. Як вам відомо, при привласненні одного об'єкту посилального типу іншому копіюється посилання, а не сам об'єкт (рис. 9.1, а). Якщо необхідно скопіювати в іншу область пам'яті поля об'єкту, можна скористатися методом MemberwiseСlone, який будь-який об'єкт успадковує від класу object. При цьому об'єкти, на які указують поля об'єкту, що у свою чергу є посиланнями, не копіюються (рис. 9.1, б). Це називається поверхневим клонуванням.

Рис. 9.1. Клонування об'єктів
Для створення повністю незалежних об'єктів необхідне глибоке клонування, коли в пам'яті створюється дублікат всього дерева об'єктів, тобто об'єктів, на які посилаються поля об'єкту, поля полів і так далі (рис. 9.1, в). Алгоритм глибокого клонування дуже складний, оскільки вимагає рекурсивного обходу всіх посилань об'єкту і відстежування циклічних залежностей.
Об'єкт, що має власні алгоритми клонування, повинен оголошуватися як спадкоємець інтерфейсу ICloneable і перевизначати його єдиний метод Clone. У лістингу 9.4 приведений приклад створення поверхневої копії об'єкту класу Monster за допомогою методу MemberwiseClone, а також реалізований інтерфейс ICloneable. У демонстраційних цілях в ім'я клона об'єкту додано слово “Клон”.
Метод MemberwiseClone можна викликати тільки з методів класу. Він не може бути викликаний безпосередньо, оскільки оголошений в класі object як захищений (protected).
Лістинг 9.5. Клонування об'єктів
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace examp58
{
class Monster : ICloneable
{
string name;
int health;
int ammo;
public Monster(int health, int ammo, string name)
{
this.health = health;
this.ammo = ammo;
this.name = name;
}
public Monster ShallowClone() // поверхнева копія
{ return (Monster)this.MemberwiseClone(); }
public object Clone() // призначена копія для користувача
{
return new Monster(this.health, this.ammo, "Клон " + this.name);
}
virtual public void Passport()
{
Console.WriteLine("Monster {0} \t health = {1} ammo = {2}",
name, health, ammo);
}
}
class Program
{
static void Main(string[] args)
{
Monster Вася = new Monster(70, 80, "Вася" );
Monster X = Вася;
X.Passport();
Monster Y = Вася.ShallowClone();
Y.Passport();
Monster Z = (Monster)Вася.Clone();
Z.Passport();
}
}
}
Об'єкт X посилається на ту ж область пам'яті, що і об'єкт Вася. Отже, якщо ми внесемо зміни до одного з цих об'єктів, це відіб'ється на іншому. Об'єкти Y і Z, створені шляхом клонування, володіють власними копіями значень полів і незалежні від початкового об'єкту.