为什么序列化回调方法不能虚拟?

时间:2017-07-19 14:22:54

标签: c# .net serialization json.net

我有一个反序列化方法(用[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”。这真的是我唯一的选择吗?为什么序列化回调方法不能虚拟?

2 个答案:

答案 0 :(得分:2)

由于BinaryFormatterDataContractSerializer在反序列化时不调用构造函数,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功能。

因此,在测试之后,我很乐意按照我发布的方式进行操作。