Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

Interface ICloneable ใน C#

Interface ICloneable ใน C#

ICloneable ให้วิธีมาตรฐานในการสร้าง Copy (Clone) ของ Object มีเมธอดเดียวคือ Clone()

Definition


public interface ICloneable
{
    object Clone();
}

Shallow Copy vs Deep Copy

ประเภทคำอธิบายICloneable Default
Shallow CopyCopy ค่า Field ทั้งหมด: Value Types คัดลอกค่า, Reference Types คัดลอก Reference (ชี้ Object เดียวกัน)MemberwiseClone()
Deep CopyCopy Object ทั้งหมดรวมถึง Object ที่อ้างอิง (สร้าง Instance ใหม่ทั้งหมด)ต้อง Implement เอง

ตัวอย่าง: Shallow Copy (Default Behavior)


using System;

class Person : ICloneable
{
    public string Name;           // Reference Type (Immutable แต่ Reference)
    public int Age;               // Value Type
    public Address Address;       // Reference Type (Mutable)
    
    public Person(string name, int age, Address addr)
    {
        Name = name; Age = age; Address = addr;
    }
    
    public object Clone()
    {
        // Shallow Copy: MemberwiseClone
        return this.MemberwiseClone();
    }
    
    public override string ToString() => $"{Name}, {Age}, Addr: {Address?.City}";
}

class Address
{
    public string City;
    public Address(string city) => City = city;
}

class Program
{
    static void Main()
    {
        Person p1 = new Person("Tom", 25, new Address("Bangkok"));
        Person p2 = (Person)p1.Clone(); // Shallow Copy
        
        p2.Name = "Jerry";           // String Immutable - OK (New String)
        p2.Age = 30;                 // Value Type - OK (Independent)
        p2.Address.City = "Chiang Mai"; // Reference Type - SHARED! p1.Address เปลี่ยนด้วย
        
        Console.WriteLine($"p1: {p1}"); // Tom, 25, Addr: Chiang Mai (!)
        Console.WriteLine($"p2: {p2}"); // Jerry, 30, Addr: Chiang Mai
    }
}

ตัวอย่าง: Deep Copy Implementation


public object Clone()
{
    // Deep Copy: สร้าง Object ใหม่ทั้งหมด
    return new Person(
        this.Name,           // String - Immutable, Share ได้
        this.Age,            // Value Type - Copy
        new Address(this.Address.City) // Reference Type - New Instance
    );
}

Alternative: Copy Constructor (แนะนำกว่า ICloneable)


class Person
{
    public Person(Person other) // Copy Constructor
    {
        Name = other.Name;
        Age = other.Age;
        Address = new Address(other.Address.City); // Deep Copy
    }
}

// ใช้งาน
Person p2 = new Person(p1); // ชัดเจนกว่า (Person)p1.Clone()

⚠️ ปัญหาของ ICloneable

  • Return Type เป็น object → ต้อง Cast
  • ไม่ระบุว่า Shallow หรือ Deep → Ambiguous
  • Framework Design Guidelines: หลีกเลี่ยง ICloneable ใน Public API
  • แทนที่: ใช้ Copy Constructor, Factory Method, หรือ Record Types (C# 9+)

Record Types (C# 9+) - Built-in Cloning


public record Person(string Name, int Age, Address Address)
{
    // with-expression สำหรับ Non-destructive Mutation (Deep Copy สำหรับ Reference Types ต้องจัดการเอง)
    public Person WithNewAddress(string city) => this with { Address = new Address(city) };
}