Если снова запустить приложение и просмотреть его вывод (показанный далее), то будет видно, что возвращаемый методом
Clone()
объект
Point
действительно копирует свои внутренние переменные-члены ссылочного типа (обратите внимание, что дружественные имена у
рЗ
и
р4
теперь уникальны):
***** Fun with Object Cloning *****
Cloned p3 and stored new Point in p4
Before modification:
p3: X = 100; Y = 100; Name = Jane;
ID = 51f64f25-4b0e-47ac-ba35-37d263496406
p4: X = 100; Y = 100; Name = Jane;
ID = 0d3776b3-b159-490d-b022-7f3f60788e8a
Changed p4.desc.petName and p4.X
After modification:
p3: X = 100; Y = 100; Name = Jane;
ID = 51f64f25-4b0e-47ac-ba35-37d263496406
p4: X = 9; Y = 100; Name = My new Point;
ID = 0d3776b3-b159-490d-b022-7f3f60788e8a
Давайте подведем итоги по процессу клонирования. При наличии класса или структуры, которая содержит только типы значений, необходимо реализовать метод
Clone()
с использованием метода
MemberwiseClone()
. Однако если есть специальный тип, поддерживающий ссылочные типы, тогда для построения глубокой копии может потребоваться создать новый объект, который учитывает каждую переменную-член ссылочного типа.
Интерфейс IComparable
Интерфейс
System.IComparable
описывает поведение, которое позволяет сортировать объекты на основе указанного ключа. Вот его формальное определение:
// Данный интерфейс позволяет объекту указывать
// его отношение с другими подобными объектами
public interface IComparable
{
int CompareTo(object o);
}
На заметку! Обобщенная версия этого интерфейса (
IСоmраrаble<Т>
) предлагает более безопасный в отношении типов способ обработки операций сравнения объектов. Обобщения исследуются в главе 10.
Создайте новый проект консольного приложения по имени
ComparableCar
, скопируйте классы
Car
и
Radio
из проекта
SimpleException
, рассмотренного в главе 7, и поменяйте пространство имен в каждом файле класса на
ComparableCar
. Обновите класс
Car
, добавив новое свойство для представления уникального идентификатора каждого автомобиля и модифицированный конструктор:
using System;
using System.Collections;
namespace ComparableCar
{
public class Car
{
...
public int CarID {get; set;}
public Car(string name, int currSp, int id)
{
CurrentSpeed = currSp;
PetName = name;
CarID = id;
}
...
}
}
Теперь предположим, что имеется следующий массив объектов
Car
:
using System;
using ComparableCar;
Console.WriteLine("***** Fun with Object Sorting *****n");
// Создать массив объектов Car.
Car[] myAutos = new Car[5];
myAutos[0] = new Car("Rusty", 80, 1);
myAutos[1] = new Car("Mary", 40, 234);
myAutos[2] = new Car("Viper", 40, 34);
myAutos[3] = new Car("Mel", 40, 4);
myAutos[4] = new Car("Chucky", 40, 5);
Console.ReadLine();
В классе
System.Array
определен статический метод по имени
Sort()
. Его вызов для массива внутренних типов (
int
,
short
,
string
и т.д.) приводит к сортировке элементов массива в числовом или алфавитном порядке, т.к. внутренние типы данных реализуют интерфейс
IComparable
. Но что произойдет, если передать методу
Sort()
массив объектов
Car
?
// Сортируются ли объекты Car? Пока еще нет!
Array.Sort(myAutos);
Запустив тестовый код, вы получите исключение времени выполнения, потому что класс
Car
не поддерживает необходимый интерфейс. При построении специальных типов вы можете реализовать интерфейс
IComparable
, чтобы позволить массивам, содержащим элементы этих типов, подвергаться сортировке. Когда вы реализуете детали
СоmраrеТо()
, то должны самостоятельно принять решение о том, что должно браться за основу в операции упорядочивания. Для типа
Car
вполне логичным кандидатом может служить внутреннее свойство
CarID
:
// Итерация по объектам Car может быть упорядочена на основе CarID.
public class Car : IComparable
{