Язык программирования C#9 и платформа .NET5
Шрифт:
{
public int X { get; set; }
public int Y { get; set; }
public PointDescription desc = new PointDescription;
public Point(int xPos, int yPos, string petName)
{
X = xPos; Y = yPos;
desc.PetName = petName;
}
public Point(int xPos, int yPos)
{
X = xPos; Y = yPos;
}
public Point { }
//
Переопределить Object.ToString.
public override string ToString
=> $"X = {X}; Y = {Y}; Name = {desc.PetName};\nID = {desc.PointID}\n";
// Возвратить копию текущего объекта.
public object Clone => this.MemberwiseClone;
}
Обратите внимание, что метод
Clone
пока еще не обновлялся. Следовательно, когда пользователь объекта запросит клонирование с применением текущей реализации, будет создана поверхностная (почленная) копия. В целях иллюстрации модифицируйте вызывающий код, как показано ниже:
Console.WriteLine("***** Fun with Object Cloning *****\n");
...
Console.WriteLine("Cloned p3 and stored new Point in p4");
Point p3 = new Point(100, 100, "Jane");
Point p4 = (Point)p3.Clone;
Console.WriteLine("Before modification:"); // Перед модификацией
Console.WriteLine("p3: {0}", p3);
Console.WriteLine("p4: {0}", p4);
p4.desc.PetName = "My new Point";
p4.X = 9;
Console.WriteLine("\nChanged p4.desc.petName and p4.X");
Console.WriteLine("After modification:"); // После модификации
Console.WriteLine("p3: {0}", p3);
Console.WriteLine("p4: {0}", p4);
Console.ReadLine;
В приведенном далее выводе видно, что хотя типы значений действительно были изменены, внутренние ссылочные типы поддерживают одни и те же значения, т.к. они "указывают" на те же самые объекты в памяти (в частности, оба объекта имеют дружественное имя
Му new Point
):
***** Fun with Object Cloning *****
Cloned p3 and stored new Point in p4
Before modification:
p3: X = 100; Y = 100; Name = Jane;
ID = 133d66a7-0837-4bd7-95c6-b22ab0434509
p4: X = 100; Y = 100; Name = Jane;
ID = 133d66a7-0837-4bd7-95c6-b22ab0434509
Changed p4.desc.petName and p4.X
After modification:
p3: X = 100; Y = 100; Name = My new Point;
ID = 133d66a7-0837-4bd7-95c6-b22ab0434509
p4: X = 9; Y = 100; Name = My new Point;
ID = 133d66a7-0837-4bd7-95c6-b22ab0434509
Чтобы заставить метод
Clone
создавать полную глубокую копию внутренних ссылочных типов, нужно сконфигурировать объект, возвращаемый методом MemberwiseClone
, для учета имени текущего объекта Point
(тип System.Guid
на самом деле является структурой, так что числовые данные будут действительно копироваться). Вот одна из возможных реализаций:
// Теперь необходимо скорректировать код для учета члена.
public object Clone
{
// Сначала получить поверхностную копию.
Point newPoint = (Point)this.MemberwiseClone;
// Затем восполнить пробелы.
PointDescription currentDesc = new PointDescription;
currentDesc.PetName = this.desc.PetName;
newPoint.desc = currentDesc;
return newPoint;
}
Если снова запустить приложение и просмотреть его вывод (показанный далее), то будет видно, что возвращаемый методом
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);
}
Поделиться с друзьями: