トップ > Tech > CSharp > ディープコピー(深いコピー)をつくるCloneをジェネリック拡張メソッドでやってみた

ディープコピー(深いコピー)をつくるCloneをジェネリック拡張メソッドでやってみた

浅いコピーと深いコピー

まず、はじめにオブジェクト(インスタンス)のコピーを作ることを Clone というが、これにはシャローコピーとディープコピーがある。

浅い方は簡単

シャローコピーはオブジェクトはコピーされるが参照型のフィールドがある場合、その参照先は引き継がれる。

つまり、A をコピー元、B をクローンだとすると

A.Field => a
B.Field -> a

って感じになる。これで済む場合は

public MyClass Clone()
{
    return base.MemberwiseClone() as MyClass;
}

とでもすればいい。

.NET のオブジェクトに用意されているこの MemberWiseClone() メソッドはシャローコピーである。

深い方を考える

ディープコピーはこれからさらに全部の参照型のフィールドまでコピーしたもの。

A.Field => a
B.Field -> b

こんな感じになる。これのほうがいい場合も多い。

こちらのサイトにディープコピーのいい例がのっていた。

基本的には一度 BinaryFormatter でシリアライズしたオブジェクトをデシリアライズして他のオブジェクトに書き出すというもの。 下のほうに書かれている CloneHelper.Clone<T> が大変いい感じ。

が、ディープコピーしたいクラスすべてにこのメソッドを定義していくのは大変めんどくさい。ここでは一歩進めて、このジェネリックメソッドを拡張メソッドにしてみた。

ソースは下記の通り。

public static class Util
{
    /// <summary>
    /// ディープコピーを作成する。
    /// クローンするクラスには SerializableAttribute 属性、
    /// 不要なフィールドは NonSerializedAttribute 属性をつける。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="target"></param>
    /// <returns></returns>
    public static T CloneDeep<T>(this T target)
    {
        object clone = null;
        using (MemoryStream stream = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, target);
            stream.Position = 0;
            clone = formatter.Deserialize(stream);
        }
        return (T)clone;
    }
}

使うときは

hogehoge.CloneDeep();

とするだけ。まぁ、なんて簡単なのでしょ〜。

が、これだとすべての型に無条件に CloneDeep メソッドが追加される。必要な場合はジェネリックの型を限定したほうがいいのだが、 自分で使うだけなので、あまり気にしない。

ちなみにシリアライズするため、CloneDeep を使うクラスには SerializableAttribute 属性をつけておく必要がある。

[Serializable]
public class MyClass
{
}

以上

(2010/09/21 11:50:27)
49959
プロフィール

Kenz Yamada(山田研二)。1984年生。大阪。ちょっとずつ好きなプログラム作ってます。 好きなものはカメラと旅行。ガジェットや身の回り、ちょっとこだわります。 詳しくは Web mixi で。

Bookmark and Share