Рис. 9.1. Клонирование объектов |
Клонирование — это создание копии объекта. Копия объекта называется клоном. Как вам известно, при присваивании одного объекта ссылочного типа другому копируется ссылка, а не сам объект (рис. 9.1, а). Если необходимо скопировать в другую область памяти поля объекта, можно воспользоваться методом MemberwiseClone, который любой объект наследует от класса object. При этом объекты, на которые указывают поля объекта, в свою очередь являющиеся ссылками, не копируются (рис. 9.1, 6). Это называется поверхностным клонированием.
Для создания полностью независимых объектов необходимо глубокое клонирование, когда в памяти создается дубликат всего дерева объектов, то есть объектов, на которые ссылаются поля объекта, поля полей и т. д. (рис. 9.1, в). Алгоритм глубокого клонирования весьма сложен, поскольку требует рекурсивного обхода всех ссылок объекта и отслеживания циклических зависимостей. Объект, имеющий собственные алгоритмы клонирования, должен объявляться как наследник интерфейса ICloneable и переопределять его единственный метод Clone. В листинге 9.4 приведен пример создания поверхностной копии объекта класса Monster с помощью метода MemberwiseClone, а также реализован интерфейс ICloneable. В демонстрационных целях в имя клона объекта добавлено слово «Клон». Обратите внимание на то, что метод MemberwiseClone можно вызвать только из методов класса. Он не может быть вызван непосредственно, поскольку объявлен в классе object как защищенный (protected).
|
|
Листинг 9.4. Клонирование объектов
using System;
namespace ConsoleApplication1
{
class Monster: ICloneable
{
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);
}
string name; int health, ammo;
}
class Class1
{
static void Main()
{
Monster Вася = new Monster(70, 80, "Вася");
Monster X = Вася;
Monster Y = Bacя.ShallowClone();
Monster Z = (Monster)Bacя.Clone();
}
}
}
Объект X ссылается на ту же область памяти, что и объект Вася. Следовательно, если мы внесем изменения в один из этих объектов, это отразится на другом. Объекты Y и Z, созданные путем клонирования, обладают собственными копиями значений полей и независимы от исходного объекта.