DeepCopy.Expression – C#でディープコピー

  • 2023/5/31 内容を修正

C# でオブジェクトをディープコピーする DeepCopy.Expression というライブラリを作りました。
ディープコピーとは、オブジェクトの中に含まれるすべてのメンバや参照先のオブジェクトも新しく作成してコピーすることです。
ディープコピーするには、一般的にはシリアライズとデシリアライズを使う方法がありますが、これは速度や柔軟性に問題があります。
DeepCopy.Expression は、対象のオブジェクトの型ごとに式木を使って動的にコードを生成し、キャッシュすることで高速にコピーを行います。また [Cloneable] 属性を使ってコピーの挙動をカスタマイズすることもできます。

使い方

DeepCopy.Expression の使い方はとても簡単です。ObjectCloner クラスの Clone メソッドか CopyTo メソッドを呼び出すだけです。
Clone メソッドは、引数に渡したオブジェクトのディープコピーを作成して返します。CopyTo メソッドは、第一引数に渡したオブジェクトの内容を第二引数に渡したオブジェクトにコピーします。どちらのメソッドも、対象のオブジェクトが配列や匿名型であっても問題ありません。

例えば、以下のようなコードでディープコピーすることができます。

var target = new TestObject(); // コピーするオブジェクト
var cloned = ObjectCloner.Clone(target); // ディープコピーを作成

// 又は
TestObject destination;
ObjectCloner.CopyTo(target, destination); // ディープコピーを行う

パフォーマンス

DeepCopy.Expression のパフォーマンスは、他のライブラリと比べても優れています。以下は、同じオブジェクトを異なる回数だけディープコピーしたときの処理時間を比較したものです。

ライブラリ1回100回2,500回10,000回
A97 msec105 msec120 msec130 msec
B28 msec32 msec41 msec50 msec
C0 msec0 msec13 msec38 msec
DeepCopy.Expression27 msec28 msec31 msec38 msec

この結果からわかるように、DeepCopy.Expression は初回以降のディープコピーでは高速です。初回では式木の生成とコンパイルが行わるため、他のライブラリより遅くなりますが、その後はキャッシュされたコードで高速に処理されます。

コピーに使用したのは次のようなオブジェクトです。

using 

class TestObject
{
    int _num;
    string _name;
    DateTime _date;
    int[] _array;
 
    public static TestObject Create()
    {
        var random = new Random(Environment.TickCount);

        var instance = new TestObject();
        instance._num = random.Next();
        instance._name = random.Next().ToString();
        instance._date = DateTime.Now;
        instance._array = new int[1024];
        for (int i = 0; i < 1024; ++i)
            instance._array[i] = random.Next();

        return instance;
    }
}

尚、 Ver 1.1.0 からは事前にキャッシュを生成しておく機能を実装しています。こうすることで、初回のコピー時から高速に動作させることが可能になっています。

まとめ

同じ型のオブジェクトを繰り返しディープコピーする必要があり、速度が求められるようなケースでは DeepCopy.Expression は有用ではないでしょうか。アプリの初期化時等で事前にキャッシュ生成しておけるならば、型毎に専用のディープコピーコードを書いた時と同等近い速度が得られます。

DeepCopy.Expression は、NuGetからダウンロードできます。詳細な使い方やソースコードは GitHub で確認できます。

2件のコメント

  1. yukimakura
    2023年8月12日

    素晴らしいです…
    控えめに言ってもっと評価されるべきな気がします。
    式木活用の好例ですね!

    ライブラリCが気になるところです(^_^;)

    返信
    1. lumiria
      2023年8月13日

      コメントありがとうございます。
      式木を使うことで初回のコンパイルにどうしても時間が掛かりますが、それが許容できるケースでは高速にコピー出来るようになりました。
      現行版ではオブジェクトの構成によってはコピーできないものもあるため、その修正版を近いうちにリリース出来るように準備中です。

      返信

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

先頭に戻る