public PointDescription desc = new PointDescription;
public Point{}
public Point (int x, int y) {
this.x = x;
this.у = у;
}
public Point(int x, int y, string petname) {
this.x = x;
this.у =
у;
desc.petName = petname;
}
public object Clone { return this.MemberwiseClone; }
public override string ToString {
return string.Format("X = {0}; Y = {1}; Имя = (2};\nID = {3}\n", x, y, desc.petName, desc.pointID);
}
}
He забудьте о том. что вы еще не обновили метод Clone. Поэтому при запросе клонирования объекта пользователем с помощью данной реализации все равно будет получена поверхностная ("почленная") копия. Для примера предположим, что мы обновили метод Main так, как показано ниже.
static void Main(string[] args) {
Console.WriteLine("***** Забавы с ICloneable *****\n");
Console.WriteLine("Клонирован р3, новый Point сохранен в р4");
Point p3 = new Point(100, 100, "Jane");
Point p4 = (Point)p3.Clone;
Console.WriteLine("До модификации:");
Console.WriteLine("р3: {0}", р3);
Console.WriteLine("p4: {0}", p4);
p4.desc.petName = "Мистер X";
p4.x = 9;
Console.WriteLine("Изменены p4.desc.petName и р4.х");
Console.WriteLine("После модификации: ");
Console.WriteLine("p3: {0}", р3);
Console.WriteLine("p4: {0}", p4);
}
На рис. 7.8 показан соответствующий вывод.
Рис. 7.8. Метод MemberwiseClone возвращает поверхностную копию объекта
Для того чтобы метод Clone возвращал полные копии внутренних ссылочных типов, нужно "научить" возвращаемый методом MemberwiseClone объект учитывать текущее имя объекта Point (тип System.Guid является структурой, так что на самом деле копируются числовые данные). Вот одна из возможных реализаций.
// Мы должны учесть наличие члена PointDescription.
public object Clone {
Point newPoint = (Point)this.MemberwiseClone;
PointDescription currentDesc = new PointDescription;
сurrentDesc.petName = this.desc.petName;
newPoint.desc = currentDesc;
return newPoint;
}
Если
выполнить приложение теперь, то вы увидите (рис. 7.9), что возвращенный методом Clone объект Point действительно копирует внутренние ссылочные члены-переменные типа (обратите внимание на то, что здесь p3 и p4 имеют свои уникальные имена).
Итак, в том случае, когда класс или структура содержит только типы, характеризуемые значениями, лучше реализовать метод Clone, использующий MemberwiseClone. Однако в том случае, когда пользовательский тип содержит ссылочные типы, вы должны создать новый тип, принимающий во внимание все члены-переменные ссылочного типа.
Рис. 7.9. Здесь получена полная копия объекта
Исходный код. Проект CloneablePoint размещен в подкаталоге, соответствующем главе 7.
Создание сравнимых объектов (IComparable)
Интерфейс System.IComparable определяет поведение, позволяющее сортировать объекты по заданному ключу. Вот формальное определение.
// Этот интерфейс позволяет объекту указать его связь
// с другими подобными объектами.
public interface IComparable {
int CompareTo(object o);
}
Предположим теперь, что класс Car поддерживает некоторый внутренний идентификатор (представленный целым числом, хранимым в переменной carID), значение которого можно устанавливать с помощью параметра конструктора и изменять с помощью нового свойства ID. Ниже показана соответствующая модификация типа Car.
public class Car {
…
private int carID;
public int ID {
get { return carID; }
set { carID = value; }
}
public Car(string name, int currSp, int id) {
currSpeed = currSp;
petName = name;
carID = id;
}
…
}
Пользователи объекта могут создать массив типов Car так.