C# オブジェクトのコピー

ディープコピー

オブジェクトをディープコピーする方法です。
コピーする型には SerializableAttribute 属性をつける必要があります。
コピーが不要なフィールドには NonSerializedAttribute 属性をつけることで
シリアライズの対象から除外されます。


[SerializableAttribute()]
public class SerializableClass
{
  public int SerializableField;

  // このフィールドはコピーされません。
  [NonSerializedAttribute()]
  public int NonSerializableField;

  public SerializableClass Clone()
  {
    object clone;
    using (MemoryStream stream = new MemoryStream())
    {
      BinaryFormatter formatter = new BinaryFormatter();
      formatter.Serialize(stream, this);
      stream.Position = 0;
      clone = formatter.Deserialize(stream);
    }
    return clone as SerializableClass;
  }
}

使いかたは以下のとおりです。

SerializableClass serializable = new SerializableClass();
serializable.SerializableField = 10;
serializable.NonSerializableField = 100;

SerializableClass clone = serializable.Clone();

// i には 10 が代入されます。
int i = clone.SerializableField;
// j には 0 が代入されます。(コピーされません)
int j = clone.NonSerializableField;


もちろん clone オブジェクトのプロパティを変更しても、
コピー元の serializable オブジェクトのプロパティは変更されません。

いろいろな型のクローンが必要なら次のようなヘルパークラスを用意すると
いいかもしれません。

public class CloneHelper
{
  public static T Clone<T>(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;
  }
}

次のようにクローンメソッドを定義します。

[SerializableAttribute()]
public class SerializableClass
{
  public SerializableClass Clone()
  {
    return CloneHelper.Clone<serializableclass>(this);
  }
}