がりらぼ

WindowsRuntimeの応援ブログ

C#の主要インターフェース解説:ICloneable

オブジェクトの複製

C#は自作クラスはすべて参照型として扱われます。 ですのでインスタンスを別のインスタンスにコピーしたとき、コピーされるのは実体ではなく、参照情報となります。これをシャローコピーと言います。

public class MyObject
{
    public int hoge;
    public MyObject(int hoge)
    {
        this.hoge = hoge;
    }    
}
MyObject obj1 = new MyObject(1);
MyObject obj2 = obj1;   //コピーされるのは参照情報

obj2.hoge = 4;      //obj2の値を変えると

Console.WriteLine(obj1.hoge);   //同じ参照先だからobj1も4になってしまう

ですが、自作クラスのオブジェクトの複製をしたいときがあります。

そのようなときにICloneableインターフェースを使用します。

ICloneable

ICloneableでは、「Cloneメソッドによってオブジェクトが複製されること」を保証します。

なので、ICloneableインターフェースを実装するクラスは、Cloneメソッドでオブジェクトを複製し、別の参照先となる同じオブジェクトを複製しなければなりません。これをディープコピーと言います。

public class MyObject:ICloneable
{
    public int hoge;
    public MyObject(int hoge)
    {
        this.hoge = hoge;
    }
    public object Clone()
    {
        return new MyObject(this.hoge); //同じものを複製する
    }
}

これであとはCloneメソッドを実行すると、新しい参照先にオブジェクトが複製され、ディープコピーが実現されます。

class Program
{
    static void Main(string[] args)
    {
        MyObject obj1 = new MyObject(1);
        MyObject obj2 = (MyObject)obj1.Clone();   //新しい参照先が代入される

        obj2.hoge = 4;      //obj2の値を変えると

        Console.WriteLine(obj1.hoge);   //チガウ参照先だから値が変化しない
    }
}

まとめ

  • C#にはディープコピーとシャローコピーがある
  • ICloneableインターフェースはCloneメソッドでディープコピーを保証する

追記

LINQ神ことMVP for VisualC#のneueccさんいわく、ICloneableインタフェースはレガシーインターフェースらしく、今では推奨されていないらしいです。

なのでオブジェクトのディープコピーをするときは、それ用のメソッドを用意するかコピーコンストラクタなどをつくるとよいらしいです。