ジェネリックとシリアライズを利用したオブジェクトのディープコピー
C#やVB.NETではオブジェクトのCloneを行うと参照のみがコピー(シャローコピー)される。
シャローコピーは、値を変更するとコピー元のデータも変更されてしまうので、なにかと都合がよくないことが多い。
オブジェクトのバックアップを取りたいような場合は値そのものをコピー(ディープコピー)するように実装しなければならない。
最も楽な方法は、オブジェクトをシリアライズし、それを別オブジェクトにデシリアライズする方法。
面倒くさがり屋さんは、とりあえずSerializableAttribute属性つけてコピりましょってゆー(^ω^;)
以下、C#によるサンプル。
using System; using System.IO; using System.Collections.Generic; using System.Runtime.Serialization.Formatters.Binary; namespace ClassLibrary1 { public static class General { /// <summary> /// 対象オブジェクトのディープコピークローンを取得します。 /// </summary> /// <typeparam name="T">対象オブジェクトの型</typeparam> /// <param name="target">コピー対象オブジェクトを指定します。</param> /// <returns>ディープコピーのクローンを返します。</returns> /// <remarks>このメソッでディープコピーするには、対象クラスがシリアライズ可能である必要があります。</remarks> public static T DeepCopyClone<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; } } }
また、.NET Framework2.0からは、バージョン トレラントなシリアル化*1がサポートされている。
トレラントとは「寛容な」という意味で、バージョンの変化に寛容なシリアル化という意味。
.NET Framework1.1 までのシリアル化 / 逆シリアル化は厳密に同一オブジェクトである必要があったが、
.NET Framework2.0からは、古いバージョンから単に項目が追加になっただけのデータを開いた場合には、
新たに追加された項目にNull (Nothing)が設定されているだけでよいんじゃないの?という場合が多いので、
そのような場合には、 追加した項目に対してOptionalFieldAttribute属性を付加するといい。
MSDN:バージョン トレラントなシリアル化
http://msdn.microsoft.com/ja-jp/library/ms229752(VS.80).aspx
*1:VTS:Version Tolerant Serialization