どんなオブジェクトでもコピーできる汎用のディープコピー処理(ICloneable, MemberWiseClone, Serializable, BinaryFormatter, MemoryStream)

シリアライズを利用した汎用のオブジェクトのディープコピー処理について整理しました。BinaryFormatterを使用してMemoryStreamに対してシリアライズ/デシリアライズを行いオブジェクトのメモリイメージのコピーを作成するテクニックです。理論上、Serializable属性を付与したすべてのオブジェクトに対してディープコピーが可能になります。

ICloneableインタフェース、MemberWiseCloneメソッドを使用したシャローコピーについては以下の記事を参考にしてください。
■オブジェクトのコピー。ICloneableインタフェース、MemberWiseClone、シリアライズを利用したインスタンスのコピー。
http://d.hatena.ne.jp/tekk/20091012/1255362429

C#
ジェネリック版と拡張メソッド版の2種を用意してみました。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace DeepCopyCSharp
{
class Program
{
[Serializable()]
public class item{
public int id;
public string name;
}

static void Main(string[] args)
{

item a = new item();
a.id = 12345;
a.name = "hello";

item b;

// 拡張メソッド
b = (item)a.DeepCopy();

// ジェネリックメソッド

b = DeepCopyHelper.DeepCopy(a);

b.id = 54635;

Console.ReadLine();
}

}

static class DeepCopyUtils
{
public static object DeepCopy(this object target)
{

object result;
BinaryFormatter b = new BinaryFormatter();

MemoryStream mem = new MemoryStream();

try
{
b.Serialize(mem, target);
mem.Position = 0;
result = b.Deserialize(mem);
}
finally
{
mem.Close();
}

return result;

}
}

public static class DeepCopyHelper
{
public static T DeepCopy(T target)
{

T result;
BinaryFormatter b = new BinaryFormatter();

MemoryStream mem = new MemoryStream();

try
{
b.Serialize(mem, target);
mem.Position = 0;
result = (T)b.Deserialize(mem);
}
finally
{
mem.Close();
}

return result;

}
}

}

VB.NET
ジェネリック版と拡張メソッド版の2種を用意してみました。


Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Runtime.CompilerServices

Public Class Form1

_
Public Class item
Public id As Integer
Public name As String
End Class

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim a As New item
a.id = 12345
a.name = "hello"

' 拡張メソッド
Dim b As item = CType(a.DeepCopy, item)

' ジェネリック
b = DeepCopyHelper.DeepCopy(a)

b.id = 54354

MsgBox(a.id)

End Sub

End Class

Public Module DeepCopyUtils

_
Public Function DeepCopy(ByVal target As Object) As Object

Dim result As Object
Dim b As New BinaryFormatter

Dim mem As New System.IO.MemoryStream()

Try

b.Serialize(mem, target)
mem.Position = 0
result = b.Deserialize(mem)

Finally

mem.Close()

End Try

Return result

End Function

End Module

Public Class DeepCopyHelper

Public Shared Function DeepCopy(Of T)(ByVal target As T) As T

Dim result As T
Dim b As New BinaryFormatter

Dim mem As New System.IO.MemoryStream()

Try

b.Serialize(mem, target)
mem.Position = 0
result = CType(b.Deserialize(mem), T)

Finally

mem.Close()

End Try

Return result

End Function

End Class