2

オブジェクトを手動でシリアル化する方法について先週この質問をしましたが、それ以来、私の問題を解決する汎用ラッパーを作成しようとしています。(私はサードパーティのコードの間で立ち往生しているので、このようにしています。) イベントを除いて、ほとんどすべてが機能しています。

逆シリアル化するときにオブジェクトの新しいインスタンスを技術的に作成しているため、イベント サブスクリプションは保持されなくなりました。サブスクリプションをコピーする方法、または逆シリアル化されたバージョンのすべてのイベントを元のバージョンに転送する方法はありますか?

ここに私が現在使用しているものに似たものがあります:

[Serializable]
public class Wrapper<T> : ISerializable
{
    public T Wrappee { get; set; }

    public Wrapper(T wrappee)
    {
        Wrappee = wrappee;
    }

    protected Wrapper(SerializationInfo info, StreamingContext context)
    {
        Wrappee = (T)FormatterServices.GetUninitializedObject(typeof(T));

        FieldInfo[] fields = typeof(T).GetFields();
        foreach (FieldInfo fieldInfo in fields)
        {
            var value = info.GetValue(fieldInfo.Name, fieldInfo.FieldType);
            fieldInfo.SetValue(Wrappee, value);
        }
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        FieldInfo[] fields = typeof(T).GetFields();
        foreach (FieldInfo fieldInfo in fields)
        {
            var value = fieldInfo.GetValue(Wrappee);
            info.AddValue(fieldInfo.Name, value);
        }
    }
}

まあ、それはそれの一般的な考えです。基本的に、フィールドで行ったのと同様の方法でイベントを行う方法があるかどうか疑問に思っていました。同じ方法で EventInfo を取得できることはわかっていますが、これがサブスクリプションの修正にどのように変換されるかはわかりません。

どんな助けでも大歓迎です。

編集 私はまだこれを行う方法を見つけようとしていますが、この質問に出くわしました。私はこのようなことをして、その側でサブスクリプションを修正することなく、イベントを元の appdomain に転送することができますか?

4

1 に答える 1

3

この質問は、オブジェクト グラフをシリアル化する方法に関する質問に関連しています。イベントは、オブジェクトへの参照と、これらのオブジェクトのメソッドへの参照を保持します。オブジェクト グラフをシリアル化するにはどうすればよいですか?

シリアル化する各オブジェクトに一意の ID を付与します。この ID をオブジェクトに保存したくない場合は、Dictionary<TObject, TID>. 最初のパスで ID を生成し、辞書に追加します。2 番目のパスでは、オブジェクトを ID と共にシリアル化します。他のオブジェクトへの参照の代わりに、辞書にある関連オブジェクトの ID をシリアル化します。

イベントの場合、参照されるオブジェクトの ID に加えてメソッド名を保存します。

オブジェクトを逆シリアル化するときは、逆引き辞書が必要になります: Dictionary<TID, TObject>. 最初のパスで、オブジェクトをデシリアライズし、それらの ID をキーとするディクショナリに追加します。また、逆シリアル化されたオブジェクトをリストに追加します。2 番目のパスでは、リストを調べて、参照とイベントを修正します。

これにより、可能な手順のアイデアが得られることを願っています。


アップデート

GetInvocationListメソッドでイベント情報を取得できます

class ClassWithEvent
{
    public event EventHandler SomeEvent;

    public Delegate[] GetSomeEventInvocationList()
    {
        return SomeEvent.GetInvocationList();
    }
}

メソッドをテストしました

class Subscriber
{
    public void SomeMethod(object sender, EventArgs e)
    {
    }
}

static class Serialize
{
    public static void Test()
    {
        var objWithEvent = new ClassWithEvent();
        var subscriber1 = new Subscriber();
        var subscriber2 = new Subscriber();

        objWithEvent.SomeEvent += subscriber1.SomeMethod;
        objWithEvent.SomeEvent += subscriber2.SomeMethod;

        Delegate[] eventInfo = objWithEvent.GetSomeEventInvocationList();
        foreach (Delegate d in eventInfo) {
            Console.WriteLine("Target = {0},   Method = {1}", 
                              d.Target, d.Method.Name);
        }
    }
}

これを呼び出すSerialize.Test();とコンソールに出力されます

ターゲット = StackOverflowTests.SerializeEvent.Subscriber、メソッド = SomeMethod
ターゲット = StackOverflowTests.SerializeEvent.Subscriber、メソッド = SomeMethod

于 2012-07-04T19:58:48.503 に答える