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



我有一个反序列化方法(用[OnDeserialized()]属性装饰(,我想在派生类中覆盖它。当我尝试这样做时,我收到以下运行时错误:

类型为"System.TypeLoadException"的未处理异常...。 在程序集中键入"BaseObj" ...具有方法"OnDeserialization",该方法可以是静态的、虚拟的、抽象的或泛型的,但被标记为序列化回调方法。

我找不到任何文档确认对序列化回调的这种限制(除了错误消息本身(。谁能解释这个奇怪的限制?

根据此处评论中的建议,我求助于从 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.";
}    
}

这似乎工作正常,但似乎相当"笨拙"。这真的是我唯一的选择吗?为什么序列化回调方法不能是虚拟的?

我遇到了同样的问题,我看到了这个问题。所以我做了一些测试,我得到了一些有趣的发现,我想我从不同的角度弄清楚了为什么不需要虚拟。 这是我的测试。

[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,仍会调用 Base 类的 OnDeserializedBase

如果是这种情况,使此方法虚拟化没有任何好处。因为,要获得虚拟方法的好处,您需要将派生对象传递到基对象中,并调用该 base.virtualMethod((。永远没有机会这样做。但是,即使反序列化派生类,也不必担心丢失 OnDeserialized 功能。

所以在测试之后,我很乐意按照我发布的方式去做。

由于BinaryFormatterDataContractSerializer在反序列化时不调用构造函数,因此OnDeserializedAttribute允许执行通常在构造函数中执行的操作,例如状态初始化。此属性标记的方法也按照构造函数的相同顺序执行:首先是基,然后派生。

因此,出于反序列化的目的,您可以将这些方法视为构造函数。

C# 中不允许使用虚拟构造函数。

最新更新