MemberwiseCloneを説明する

概要

C#に組み込み関数として用意されている「MemberwiseClone」関数を理解して、使えるようになりたい方への記事。

結論

MemberwiseCloneはオブジェクトをShallowCopyする。

解説

型を知ろう

C#には値型と参照型が定義されている。

値型は値そのものを、参照型は参照を保持している。

値型

値型は、データそのものを直接保持し、メモリ上の スタック(Stack) に格納されます。
代入やコピー時には 値そのものがコピー されるため、元の変数には影響を与えません。

代表的な値型
  • 基本データ型:int, double, char, bool
  • 構造体(struct):DateTime, Point など
  • 列挙型(enum)
値型の動作
int a = 10;
int b = a; // 値がコピーされる

b = 20;
Console.WriteLine(a); // 10(元の値は変わらない)
Console.WriteLine(b); // 20

参照型

参照型は、データそのものではなく、データが格納されているメモリのアドレス(参照)を保持 します。
そのため、メモリ上の ヒープ(Heap) に格納されます。

代入やコピー時には 参照(アドレス)がコピー されるため、複製した変数を変更すると元の変数も影響を受けます。

代表的な参照型
  • クラス(class):string, List, object など
  • 配列(array):int[], string[]
  • デリゲート(delegate)

参照型の動作

class Person
{
    public string Name;
}

Person p1 = new Person { Name = "Alice" };
Person p2 = p1; // 参照(アドレス)がコピーされる

p2.Name = "Bob"; // p2 を変更

Console.WriteLine(p1.Name); // "Bob"(p1 も影響を受ける)

コピーには種類があることを知ろう

あるオブジェクトを複製(コピー)したい場合、その方法は2種類存在する。
1つ目は浅いコピー、2つ目は深いコピー。

この2つを使い分ける際に、参照型をフィールドに持つかが重要になってくる。

浅いコピー(Shallow Copy)とは?

「オブジェクトのトップレベルのフィールドのみをコピーする」 方法です。
値型のフィールドは値がコピーされますが、参照型のフィールドはアドレス(参照)だけがコピーされます。
つまり、コピー後のオブジェクトと元のオブジェクトは、参照型のフィールドを共有 することになります。

class Address
{
    public string City;
}

class Person
{
    public string Name;  // 値型
    public int Age;      // 値型
    public Address Address; // 参照型

    public Person ShallowCopy()
    {
        return (Person)this.MemberwiseClone();
    }
}

class Program
{
    static void Main()
    {
        Person original = new Person { Name = "Alice", Age = 25, Address = new Address { City = "Tokyo" } };
        Person copy = original.ShallowCopy(); // 浅いコピーを作成

        copy.Name = "Bob";        // コピーの Name を変更(影響なし)
        copy.Age = 30;            // コピーの Age を変更(影響なし)
        copy.Address.City = "Osaka"; // コピーの Address.City を変更(影響あり)

        Console.WriteLine(original.Name); // "Alice"(影響なし)
        Console.WriteLine(original.Age);  // 25(影響なし)
        Console.WriteLine(original.Address.City); // "Osaka"(影響を受けた!)
    }
}
浅いコピーのポイント

値型フィールド(Age)は独立してコピーされるため、変更しても影響しない。
参照型フィールド(Address)は共有されるため、コピー先で変更すると元のオブジェクトも影響を受ける。

深いコピー(Deep Copy)とは?

「オブジェクトのすべてのフィールドを、新しいインスタンスとして再帰的にコピーする」 方法です。
参照型のフィールドも 新しいインスタンスを作成 するため、コピー後のオブジェクトは元のオブジェクトと完全に独立します。

class Address
{
    public string City;

    public Address DeepCopy()
    {
        return new Address { City = this.City }; // 新しい Address インスタンスを作成
    }
}

class Person
{
    public string Name;
    public int Age;
    public Address Address;

    public Person DeepCopy()
    {
        return new Person
        {
            Name = this.Name,
            Age = this.Age,
            Address = this.Address.DeepCopy() // Address も新しく作成
        };
    }
}

class Program
{
    static void Main()
    {
        Person original = new Person { Name = "Alice", Age = 25, Address = new Address { City = "Tokyo" } };
        Person copy = original.DeepCopy(); // 深いコピーを作成

        copy.Name = "Bob";        // 影響なし
        copy.Age = 30;            // 影響なし
        copy.Address.City = "Osaka"; // 影響なし(独立している!)

        Console.WriteLine(original.Name); // "Alice"(影響なし)
        Console.WriteLine(original.Age);  // 25(影響なし)
        Console.WriteLine(original.Address.City); // "Tokyo"(影響なし!)
    }
}

MemberwiseCloneと=代入演算子は異なる

あれ?これなら新しく変数を用意して代入すればよくない?と思った方。
それは間違えです。
代入は値型は値をそのまま、参照型は参照を代入します。

詳しい説明

参照型を、新しい変数に
1.代入した場合
2.MemberwiseCloneでオブジェクトを作成し、それを代入した場合。

1の場合は参照を代入しているので、参照したインスタンスが値型を持っている場合、代入先の変数がもつ値型を変更すると、元のインスタンスの値も変更される。

2の場合はインスタンス自体の参照は異なるので、値型を変更しても元のインスタンスが持つ値は変更されない。

参照元

Object.MemberwiseClone メソッド

C#,Unity

Posted by admin