Язык программирования C#9 и платформа .NET5
Часть 179 из 642 Информация о книге
using System;namespace CloneablePoint{// Этот класс описывает точку.public class PointDescription{public string PetName {get; set;}public Guid PointID {get; set;}public PointDescription(){PetName = "No-name";PointID = Guid.NewGuid();}}}Начальные изменения самого класса
включают модификацию методаPointдля учета новых данных состояния, а также определение и создание ссылочного типаToString(). Чтобы позволить внешнему миру устанавливать дружественное имя дляPointDescription, необходимо также изменить аргументы, передаваемые перегруженному конструктору:Pointpublic class Point : ICloneable{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 p4Before modification:p3: X = 100; Y = 100; Name = Jane;ID = 133d66a7-0837-4bd7-95c6-b22ab0434509p4: X = 100; Y = 100; Name = Jane;ID = 133d66a7-0837-4bd7-95c6-b22ab0434509Changed p4.desc.petName and p4.XAfter modification:p3: X = 100; Y = 100; Name = My new Point;ID = 133d66a7-0837-4bd7-95c6-b22ab0434509p4: 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;}