我有一个反序列化方法(用[OnDeserialized()]
属性修饰),我想在派生类中覆盖它。当我尝试这样做时,我得到以下运行时错误:
类型'System.TypeLoadException'的未处理异常.... 在程序集中输入'BaseObj'有方法'OnDeserialization',它是静态的,虚拟的,抽象的或通用的,但被标记为序列化回调方法。
我找不到任何确认序列化回调限制的文档(错误消息本身除外)。任何人都可以解释这个奇怪的限制吗?
根据评论here中的建议,我使用OnDeserialization方法调用一个单独的虚函数,如下所示:
[Serializable()]
public class BaseObj
{
protected string obj { get; set; }
[OnDeserialized()]
public void OnDeserializedMethod(StreamingContext context)
{
//call the virtual method because deserialization callbacks can’t be virtual
onDeserialized(context);
}
virtual protected void onDeserialized(StreamingContext context)
{
obj = "This value was deserialized by the base class.";
}
}
[Serializable()]
public class DerivedObj : BaseObj
{
override protected void onDeserialized(StreamingContext context)
{
obj = "This value was deserialized by the derived class.";
}
}
这似乎工作正常,但似乎相当“kludgey”。这真的是我唯一的选择吗?为什么序列化回调方法不能虚拟?
答案 0 :(得分:2)
由于BinaryFormatter
和DataContractSerializer
在反序列化时不调用构造函数,OnDeserializedAttribute
允许执行通常在构造函数中执行的操作,例如状态初始化。由此属性标记的方法也以相同的顺序执行构造函数:首先是base,然后是派生的。
因此,为了反序列化,您可以将这些方法视为构造函数。
虚拟构造函数are not allowed in C#。
答案 1 :(得分:1)
我面临着同样的问题,我看到了这个问题。因此,我进行了一些测试,得出了一些有趣的发现,并且我认为我从不同的角度指出了为什么不需要虚拟。 这是我的考试。
[DataContract]
class Base
{
[OnDeserialized]
//cannot be virtual
protected void OnDeserializedBase()
{
//base deserialization
}
}
[DataContract]
public class Derived : Base
{
[OnDeserialized]
//cannot be virtual
OnDeserializedDerived()
{
//Derived deserialization
}
}
Base b = new DataContractJsonSerializer(typeof(Derived)).ReadObject(stream);
我发现的是,依次调用OnDeserializedBase和OnDeserializedDerived。即使派生类中没有OnDeserialized,基类的OnDeserializedBase仍将被调用。
如果是这种情况,则将此方法虚拟化不会带来任何好处。因为要获得虚拟方法的好处,您需要将派生对象传递给基础对象,然后调用该base.virtualMethod()。永远没有机会那样做。但是,即使反序列化派生类,也不必担心会丢失OnDeserialized功能。
因此,在测试之后,我很乐意按照我发布的方式进行操作。