ブログトップ 記事一覧 ログイン 無料ブログ開設

tekkの日記 C#,VB.NET このページをアンテナに追加 RSSフィード Twitter

人気記事 No.1 どんなオブジェクトでもコピーできる汎用のディープコピー処理

2010-01-31

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

| 13:58 | どんなオブジェクトでもコピーできる汎用のディープコピー処理(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<item>(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>(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

    <Serializable()> _
    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

    <Extension()> _
    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

vespavespa 2010/02/26 11:44 複雑な自作classをcloneするのに困っていました。
(cloneを実装するとなると相当な工数だったので)
これは素晴らしいですね。
ありがとうございます。

tekktekk 2010/02/28 21:12 私も少し前まではクラスはコピーできないものと考えていたので、シリアライズの応用を思いつくまでは、意識の外でした。使い勝手の良いテクニックなのでお勧めですよ。

あひるあひる 2010/07/24 17:11 素晴らしいの一言に尽きる。
シリアライズをこうやって使うというのは、思いつかなかったです。

jiioijiioi 2010/08/03 23:04 エクセレント!!
最高に気持ちいいですね。

会社員会社員 2011/02/21 18:13 いままでセコセコクローン処理を自作クラスで作ってたのが
アホらしくなりますね。
とても有用なコードありがとうございます。
。。。でも速度的にはどうなんでしょうかね?

howlinghowling 2012/11/07 12:20 助かりました。
ICloneableを継承すれば良かった…!と思った時すでに遅し。
シリアライズでどうにかするところまでいったのですが、
質問掲示板でヒントを頂き、こちらに辿り着きました。

ほぼほぼそのままコード使わせて頂いているのですが、大丈夫でしょうか?

osdmssosdmss 2017/07/05 10:37 素晴らしすぎる!
すいません、使わせていただきます!
感謝です!