扩展 GetObjectData 方法未标记为虚拟的 class 时的序列化
Serialization when extending a class whose GetObjectData method is not marked virtual
我正在尝试扩展一个框架。我正在扩展的 classes 之一是序列化的。基本 class' GetObjectData()
方法未标记为虚拟,因此我无法覆盖它。
现在如果对象在被引用为基础时被序列化 class 它不是多态的,所以只有基础 class' GetObjectData
被调用。
有没有办法在不修改基础 class' GetObjectData
以将其标记为虚拟的情况下解决这个问题?
[编辑] 我扩展了 class 并添加了一个我想要序列化的属性。以下问题的简单示例
[Serializable]
public class ParentClass : ISerializable
{
public float m_parent = 1.73f;
public ParentClass()
{ }
public ParentClass(SerializationInfo info, StreamingContext context)
{
Debug.Log("Loading parent");
m_parent = (float)info.GetValue("m_parent", typeof(float));
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
Debug.Log("Saving parent");
info.AddValue("m_parent", m_parent, typeof(float));
}
}
[Serializable]
public class ChildClass : ParentClass
{
public int m_child = 73;
public ChildClass()
{ }
public ChildClass(SerializationInfo info, StreamingContext context) : base(info, context)
{
Debug.Log("Loading child");
m_child = (int)info.GetValue("m_child", typeof(int));
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
Debug.Log("Saving child");
info.AddValue("m_child", m_child, typeof(int));
base.GetObjectData(info, context);
}
}
void Save()
{
Debug.Log("Starting save");
ParentClass aParent = new ChildClass() as ParentClass;
using (Stream stream = File.Open(fileName, FileMode.Create))
{
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Serialize(stream, aParent);
}
Debug.Log("Save complete");
}
void Load()
{
Debug.Log("Starting load");
ChildClass aChild;
using (Stream stream = File.Open(fileName, FileMode.Open))
{
BinaryFormatter bFormatter = new BinaryFormatter();
aChild = bFormatter.Deserialize(stream) as ChildClass;
}
Debug.Log("Load complete" + aChild.m_child);
}
执行 save/load 会产生以下错误:
SerializationException: No element named m_child could be found.
您可以使用 new modifier 覆盖基础 class 实现。
如果序列化程序 引用 基 class,这将无济于事。它必须被引用为 new
覆盖的子类型才能工作。
在这种情况下,您唯一的希望是 1) 替换序列化逻辑以便您可以控制它,2) 使用代理 class 来回映射到框架 class, 3) 分叉框架以修复其局限性或 4) magic
在不确切知道您需要 GetObjectData
的情况下,您可以在 serialization/deserialization 期间使用一些自定义方法来操作您的对象:
[Serializable]
public MySerializableClass : MyUnforgivingBaseClass
{
[OnSerializing]
public void OnSerializing(StreamingContext context)
{
//You can modify the object before serialization here
}
[OnDeserializing]
public void OnDeserializing(StreamingContext context)
{
//You can modify the object during deserialization here
}
}
见https://msdn.microsoft.com/en-us/library/system.runtime.serialization.ondeserializingattribute(v=vs.110).aspx and https://msdn.microsoft.com/en-us/library/system.runtime.serialization.onserializingattribute%28v=vs.110%29.aspx
你需要做两件事:
将 ChildClass
明确标记为 ISerializable
。
按照 Will 的建议,在子 class 中用 new
修饰符声明一个 GetObjectData
,
或
在子 class.
中显式实现接口
例如:
[Serializable]
public class ChildClass : ParentClass, ISerializable
{
public int m_child = 73;
public ChildClass()
{ }
public ChildClass(SerializationInfo info, StreamingContext context)
: base(info, context)
{
Debug.WriteLine("Loading child");
m_child = (int)info.GetValue("m_child", typeof(int));
}
public new void GetObjectData(SerializationInfo info, StreamingContext context)
{
Debug.WriteLine("Saving child");
info.AddValue("m_child", m_child, typeof(int));
base.GetObjectData(info, context);
}
}
由于 BinaryFormatter.Serialize(Stream, Object)
是非泛型的,将发现并使用最派生的接口实现。
有关其工作原理的详细信息,请参阅 c# 语言规范 Section 13.4.4 Interface re-implementation:
A class that inherits an interface implementation is permitted to re-implement the interface by including it in the base class list.
我正在尝试扩展一个框架。我正在扩展的 classes 之一是序列化的。基本 class' GetObjectData()
方法未标记为虚拟,因此我无法覆盖它。
现在如果对象在被引用为基础时被序列化 class 它不是多态的,所以只有基础 class' GetObjectData
被调用。
有没有办法在不修改基础 class' GetObjectData
以将其标记为虚拟的情况下解决这个问题?
[编辑] 我扩展了 class 并添加了一个我想要序列化的属性。以下问题的简单示例
[Serializable]
public class ParentClass : ISerializable
{
public float m_parent = 1.73f;
public ParentClass()
{ }
public ParentClass(SerializationInfo info, StreamingContext context)
{
Debug.Log("Loading parent");
m_parent = (float)info.GetValue("m_parent", typeof(float));
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
Debug.Log("Saving parent");
info.AddValue("m_parent", m_parent, typeof(float));
}
}
[Serializable]
public class ChildClass : ParentClass
{
public int m_child = 73;
public ChildClass()
{ }
public ChildClass(SerializationInfo info, StreamingContext context) : base(info, context)
{
Debug.Log("Loading child");
m_child = (int)info.GetValue("m_child", typeof(int));
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
Debug.Log("Saving child");
info.AddValue("m_child", m_child, typeof(int));
base.GetObjectData(info, context);
}
}
void Save()
{
Debug.Log("Starting save");
ParentClass aParent = new ChildClass() as ParentClass;
using (Stream stream = File.Open(fileName, FileMode.Create))
{
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Serialize(stream, aParent);
}
Debug.Log("Save complete");
}
void Load()
{
Debug.Log("Starting load");
ChildClass aChild;
using (Stream stream = File.Open(fileName, FileMode.Open))
{
BinaryFormatter bFormatter = new BinaryFormatter();
aChild = bFormatter.Deserialize(stream) as ChildClass;
}
Debug.Log("Load complete" + aChild.m_child);
}
执行 save/load 会产生以下错误:
SerializationException: No element named m_child could be found.
您可以使用 new modifier 覆盖基础 class 实现。
如果序列化程序 引用 基 class,这将无济于事。它必须被引用为 new
覆盖的子类型才能工作。
在这种情况下,您唯一的希望是 1) 替换序列化逻辑以便您可以控制它,2) 使用代理 class 来回映射到框架 class, 3) 分叉框架以修复其局限性或 4) magic
在不确切知道您需要 GetObjectData
的情况下,您可以在 serialization/deserialization 期间使用一些自定义方法来操作您的对象:
[Serializable]
public MySerializableClass : MyUnforgivingBaseClass
{
[OnSerializing]
public void OnSerializing(StreamingContext context)
{
//You can modify the object before serialization here
}
[OnDeserializing]
public void OnDeserializing(StreamingContext context)
{
//You can modify the object during deserialization here
}
}
见https://msdn.microsoft.com/en-us/library/system.runtime.serialization.ondeserializingattribute(v=vs.110).aspx and https://msdn.microsoft.com/en-us/library/system.runtime.serialization.onserializingattribute%28v=vs.110%29.aspx
你需要做两件事:
将
ChildClass
明确标记为ISerializable
。按照 Will 的建议,在子 class 中用
new
修饰符声明一个GetObjectData
,或
在子 class.
中显式实现接口
例如:
[Serializable]
public class ChildClass : ParentClass, ISerializable
{
public int m_child = 73;
public ChildClass()
{ }
public ChildClass(SerializationInfo info, StreamingContext context)
: base(info, context)
{
Debug.WriteLine("Loading child");
m_child = (int)info.GetValue("m_child", typeof(int));
}
public new void GetObjectData(SerializationInfo info, StreamingContext context)
{
Debug.WriteLine("Saving child");
info.AddValue("m_child", m_child, typeof(int));
base.GetObjectData(info, context);
}
}
由于 BinaryFormatter.Serialize(Stream, Object)
是非泛型的,将发现并使用最派生的接口实现。
有关其工作原理的详细信息,请参阅 c# 语言规范 Section 13.4.4 Interface re-implementation:
A class that inherits an interface implementation is permitted to re-implement the interface by including it in the base class list.