我问this question上周关于如何手动序列化对象,此后我一直在尝试制作通用包装器来解决我的问题。 (我这样做是因为我被困在第 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,但我不知道这将如何转化为修复订阅。
任何帮助将不胜感激。
编辑 所以我仍在尝试找到一种方法来做到这一点,我遇到了 this question.我是否能够执行类似的操作,然后将事件转发回原始应用程序域,而无需修复该端的订阅?
最佳答案
这个问题与对象图如何序列化的问题有关。事件保存对对象的引用以及对这些对象的方法的引用。对象图如何序列化?
我会给每个要序列化的对象一个唯一的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
关于c# - 如何序列化和处理通用类型中所有事件的订阅?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11334465/