如何序列化和处理泛型类型中所有事件的订阅?

时间:2012-07-04 19:22:23

标签: c# events serialization reflection remoting

我上周询问了this question关于如何手动序列化对象的问题,之后我一直试图制作能够解决我问题的通用包装器。 (我这样做是因为我遇到了第三方代码。)除了事件之外,我几乎都有工作。

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

这与我目前使用的内容类似:

[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,但我不知道这将如何转换为修复订阅。

非常感谢任何帮助。

修改 所以我仍然试图找到一种方法来实现这一点,我遇到了this question.我是否可以做这样的事情,然后将事件转发回原来的appdomain,而无需修复订阅结束?

1 个答案:

答案 0 :(得分: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();输出

  

Target = StackOverflowTests.SerializeEvent.Subscriber,Method = SomeMethod
  Target = StackOverflowTests.SerializeEvent.Subscriber,Method = SomeMethod