2010年1月15日金曜日

[.NET]シャローコピーとディープコピー

objectクラスにはMemberwiseCloneというメンバ変数をコピーしてくれるメソッドが標準で搭載されています。しかし、このメソッドはシャローコピーなので、内包しているクラスがある場合、そのオブジェクトをコピーしません。
で、コレを解決するにはディープコピーするしかないのですが、コレを簡単にやる方法としてシリアライズする方法があります。意外と簡単。コードはこんな感じ。


//using System.IO;
//using System.Runtime.Serialization.Formatters.Binary;
private void button1_Click(object sender, EventArgs e)
{
    CopyTest test1 = new CopyTest();
    System.Diagnostics.Debug.WriteLine(test1);
    //『IntData=[1] ,StringData=[1], modeText[葉]』と表示される
    test1.SetChild();

    // インスタンスをコピーする
    CopyTest test2 = test1.Clone();
    CopyTest test3 = (CopyTest)Clone(test1);

    System.Diagnostics.Debug.WriteLine(test1);
    System.Diagnostics.Debug.WriteLine(test2);
    System.Diagnostics.Debug.WriteLine(test3);
    //『IntData=[1] ,StringData=[1], modeText[枝]{IntData=[1] ,StringData=[1], modeText[葉]}』と表示される
    //『IntData=[1] ,StringData=[1], modeText[枝]{IntData=[1] ,StringData=[1], modeText[葉]}』と表示される
    //『IntData=[1] ,StringData=[1], modeText[枝]{IntData=[1] ,StringData=[1], modeText[葉]}』と表示される


    // Childのインスタンスがシャローコピーなので、test1/test2のIntDataが同じ値になる
    test2.Child.IntData = 3;
    System.Diagnostics.Debug.WriteLine(test1);
    System.Diagnostics.Debug.WriteLine(test2);
    //『IntData=[1] ,StringData=[1], modeText[枝]{IntData=[3] ,StringData=[1], modeText[葉]}』と表示される
    //『IntData=[1] ,StringData=[1], modeText[枝]{IntData=[3] ,StringData=[1], modeText[葉]}』と表示される

    // test3はディープコピーになるので、IntDataは1のまま
    System.Diagnostics.Debug.WriteLine(test3);
    //『IntData=[1] ,StringData=[1], modeText[枝]{IntData=[1] ,StringData=[1], modeText[葉]}』と表示される

}

private static object Clone(object obj)
{
    object result = null;

    using (MemoryStream ms = new MemoryStream())
    {
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(ms, obj);

        ms.Position = 0;
        result = bf.Deserialize(ms);

    }

    return result;
}

[Serializable()]
public class CopyTest
{
    public int IntData { getset; }
    public string StringData { getset; }

    private string modeText = "葉";

    public CopyTest Child { getset; }

    public CopyTest()
    {
        IntData = 1;
        StringData = "1";

    }

    public void SetChild()
    {
        modeText = "枝";
        Child = new CopyTest();
    }

    public override string ToString()
    {
        string result = "IntData=[" + IntData + "] ,StringData=[" + StringData + "], modeText[" + modeText + "]";
        if (Child != null)
        {
            result += "{" + Child.ToString() + "}";
        }
        return result;
    }

    public CopyTest Clone()
    {
        return (CopyTest)MemberwiseClone();
    }
}

0 件のコメント :