Книга: C# 4.0: полное руководство

Интерфейс ICloneable

Интерфейс ICloneable

Реализовав интерфейс ICloneable, можно создать все условия для копирования объекта. В интерфейсе ICloneable определен только один метод, Clone(), объявление которого приведено ниже.

object Clone()

В этом методе создается копия вызывающего объекта, а конкретная его реализация зависит от способа создания копии объекта. Вообще говоря, существуют две разновидности копий объектов: полная и неполная. Если создается полная копия, то копия совершенно не зависит от оригинала. Так, если в исходном объекте содержится ссылка на другой объект О, то при его копировании создается также копия объекта О. А при создании неполной копии осуществляется копирование одних только членов, но не объектов, на которые эти члены ссылаются. Так, после создания неполной копии объекта, ссылающегося на другой объект О, копия и оригинал будут ссылаться на один и тот же объект О, причем любые изменения в объекте О будут оказывать влияние как на копию, так и на оригинал. Как правило, метод Clone() реализуется для получения полной копии. А неполные копии могут быть созданы с помощью метода MemberwiseClone(), определенного в классе Object.

Ниже приведен пример программы, в которой демонстрируется применение интерфейса ICloneable. В ней создается класс Test, содержащий ссылку на объект класса X. В самом классе Test используется метод Clone() для создания полной копии.

// Продемонстрировать применение интерфейса ICloneable.
using System;
class X {
  public int a;
  public X(int x) { a = x; }
}
class Test : ICloneable {
  public X o;
  public int b;
  public Test(int x, int y) {
    o = new X(x);
    b = y;
  }
  public void Show(string name) {
    Console.Write("Значения объекта " + name + ": ");
    Console.WriteLine("o.a: {0}, b: {1}", o.a, b);
  }
  // Создать полную копию вызывающего объекта,
  public object Clone() {
    Test temp = new Test(o.a, b);
    return temp;
  }
}
class CloneDemo {
  static void Main() {
    Test ob1 = new Test(10, 20);
    ob1.Show("ob1");
    Console.WriteLine("Сделать объект ob2 копией объекта ob1.");
    Test ob2 = (Test)ob1.Clone();
    ob2.Show("ob2");
    Console.WriteLine("Изменить значение ob1.о.а на 99, " +
            " а значение ob1.b — на 88.");
    ob1.o.a = 99;
    ob1.b = 88;
    ob1.Show("ob1");
    ob2.Show("ob2");
  }
}

Ниже приведен результат выполнения этой программы.

Значения объекта оb1: о.а: 10, b: 20
Сделать объект оb2 копией объекта оb1.
Значения объекта оb2: о.а: 10, b: 20
Изменить значение ob1.о.а на 99, а значение obl.b — на 88.
Значения объекта оb1: о.а: 99, b: 88
Значения объекта оb2: о.а: 10, b: 20

Как следует из результата выполнения приведенной выше программы, объект оb2 является копией объекта оb1, но это совершенно разные объекты. Изменения в одном из них не оказывают никакого влияния на другой. Это достигается конструированием нового объекта типа Test, который выделяет новый объект типа X для копирования. При этом новому экземпляру объекта типа X присваивается такое же значение, как и у объекта типа X в оригинале.

Для получения неполной копии достаточно вызвать метод MemberwiseClone(), определяемый в классе Object из метода Clone(). В качестве упражнения попробуйте заменить метод Clone() в предыдущем примере программы на следующий его вариант.

// Сделать неполную копию вызывающего объекта,
public object Clone()    {
  Test temp = (Test) MemberwiseClone();
  return temp;
}

После этого изменения результат выполнения данной программы будет выглядеть следующим образом.

Значения объекта ob1: о.а: 10, b: 20
Сделать объект оb2 копией объекта оb1.
Значения объекта оb2: о.а: 10, b: 20
Изменить значение ob1.о.а на 99, а значение obl.b — на 88.
Значения объекта ob1: о.а: 99, b:
88 Значения объекта оb2: о.а: 99, b: 20

Как видите, обе переменные экземпляра о в объектах оb1 и оb2 ссылаются на один и тот же объект типа X. Поэтому изменения в одном объекте оказывают влияние на другой. Но в то же время поля b типа int в каждом из них разделены, поскольку типы значений недоступны по ссылке.

Оглавление книги


Генерация: 2.550. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз