[ Полезный рекламный блок ]
Попробуйте свои силы в игре, где ваши навыки программирования на C# станут решающим фактором. Переходите по ссылке 🔰.
У C# клонування об’єкта означає створення його копії. Однак існує два типи клонування: неглибоке клонування і глибоке клонування.
Під час неглибокого клонування створюється новий об’єкт, який є копією вихідного об’єкта, але вміст копії, як і раніше, вказує на ті самі об’єкти, що й оригінал. Це означає, що зміни, внесені у властивості копії, також вплинуть на оригінал.
Глибоке клонування, з іншого боку, створює новий об’єкт, який є копією оригіналу, але вміст копії також копіюється, тому два об’єкти не мають спільних посилань. Це означає, що зміни, внесені у властивості копії, не вплинуть на оригінал.
У C# існує кілька способів глибокого клонування об’єкта, включно з реалізацією інтерфейсу ICloneable, використанням серіалізації та десеріалізації, а також використанням сторонніх бібліотек, таких як AutoMapper, Newtonsoft.Json або BinaryFormatter.
Серіалізації та десеріалізація
Один із поширених підходів – використання серіалізації та десеріалізації. Ось приклад:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; [Serializable] public class MyClass { public int Number { get; set; } public string Text { get; set; } } class Program { static void Main(string[] args) { MyClass original = new MyClass { Number = 42, Text = "Hello, World!" }; // Create a memory stream and binary formatter MemoryStream stream = new MemoryStream(); BinaryFormatter formatter = new BinaryFormatter(); // Serialize the object to the memory stream formatter.Serialize(stream, original); // Reset the stream position to the beginning stream.Position = 0; // Deserialize the object from the memory stream MyClass copy = (MyClass)formatter.Deserialize(stream); // Modify the copy's properties copy.Number = 24; copy.Text = "Goodbye, World!"; // The original's properties remain unchanged Console.WriteLine(original.Number); // Output: 42 Console.WriteLine(original.Text); // Output: Hello, World! // The copy's properties have been modified Console.WriteLine(copy.Number); // Output: 24 Console.WriteLine(copy.Text); // Output: Goodbye, World! } } |
У цьому прикладі ми визначаємо простий клас MyClass, який має дві властивості: Number і Text. Потім ми створюємо екземпляр MyClass і серіалізуємо його в потік пам’яті за допомогою BinaryFormatter. Ми скидаємо позицію потоку на початок, а потім десеріалізуємо об’єкт назад у новий екземпляр MyClass під назвою copy. Нарешті, ми змінюємо властивості копії та перевіряємо, що властивості оригіналу залишилися незмінними.
Використання серіалізації та десеріалізації передбачає серіалізацію вихідного об’єкта в потік байтів, а потім його десеріалізацію назад у новий об’єкт. Цей підхід може бути повільнішим, ніж інші методи, але він часто простіший у реалізації.
Реалізація інтерфейсу ICloneable
Для початку розглянемо приклад не глибокого клонування:
1 2 3 4 5 6 7 8 9 |
class Person : ICloneable { public string Name { get; set; } public int Age { get; set; } public object Clone() { return new Person { Name = this.Name, Age = this.Age }; } } |
Використання:
1 2 3 4 5 6 7 |
static void Main() { Person p1 = new Person { Name = "Tom", Age = 23 }; Person p2 = (Person)p1.Clone(); p2.Name = "Alice"; Console.WriteLine(p1.Name); // Tom } |
Тепер приклад із глибоким клонуванням:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Person : ICloneable { public string Name { get; set; } public int Age { get; set; } public Company Work { get; set; } public object Clone() { Company company = new Company { Name = this.Work.Name }; return new Person { Name = this.Name, Age = this.Age, Work = company }; } } |
Або можна зробити так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Person : ICloneable { public string Name { get; set; } public int Age { get; set; } public Company Work { get; set; } public object Clone() { var person = (Person)this.MemberwiseClone(); person.Work = (Company)this.Work.Clone(); return person; } } class Company:ICloneable { public string Name { get; set; } public object Clone() { return this.MemberwiseClone(); } } |
Використання:
1 2 3 4 5 6 7 8 9 |
static void Main(string[] args) { Person p1 = new Person { Name = "Tom", Age = 23, Work = new Company { Name = "Microsoft" } }; Person p2 = (Person)p1.Clone(); p2.Work.Name = "Google"; p2.Name = "Alice"; Console.WriteLine(p1.Name); Console.WriteLine(p1.Work.Name); } |