我上周询问了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,而无需修复订阅结束?
答案 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