2

上周我问了这个关于如何手动序列化对象的问题,此后我一直在尝试制作通用包装器来解决我的问题。(我这样做是因为我被困在第 3 方代码之间。)除了事件之外,我几乎所有的东西都在工作。

由于我在反序列化时在技术上创建了对象的新实例,因此我不再保留我的事件订阅。有没有办法复制订阅,或者将反序列化版本的所有事件转发回原始版本?

这是类似于我目前使用的东西:

[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 并将它们添加到字典中。在第二遍中,将对象及其 ID 序列化。序列化您可以在字典中找到的相关对象的 ID,而不是引用其他对象。

对于事件,除了引用对象的 ID 之外,还存储一个方法名称。

反序列化对象时,您将需要一个反向字典:Dictionary<TID, TObject>. 在第一遍中,反序列化对象并将它们添加到由它们的 ID 键入的字典中。还将反序列化的对象添加到列表中。在第二遍中,通过列表并修复引用和事件。

我希望这能让您对可能的程序有所了解。


更新

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 回答