NetDataContractSerializer使用新属性进行反序列化

本文关键字:反序列化 属性 新属性 NetDataContractSerializer | 更新日期: 2023-09-27 18:23:42

由于缺乏任何真正的远见,我已经使用NetDataContractSerializer序列化了一大组仅用Serializable修饰的数据,现在我想添加一个新字段。我有什么选择?

原始类看起来像这样(有几个继承级别和相当多的字段):

[Serializable]
public class InheritedClass : BaseClass
{
    public string StringId { get; set; }
}

现在我想添加另一个属性,比如:

[Serializable]
public class InheritedClass : BaseClass
{
    public string StringId { get; set; }
    public int IntId { get; set; }
}

现在,当我更新类并进行反序列化时,我收到一个异常,因为新字段不存在,类似于:

Exception thrown: 'System.Runtime.Serialization.SerializationException' in System.Runtime.Serialization.dll
Additional information: Error in line 1 position 601. 'Element' '_x003C_StringId_x003E_k__BackingField' from namespace 'http://schemas.datacontract.org/2004/07/QT' is not expected. Expecting element '_x003C_IntId_x003E_k__BackingField'.

好的,这是有道理的,因为NetDataContractSerializer需要相同的类。我可以使用DataMember属性来绕过它,比如:

[DataMember(IsRequired = false)]

然后的问题是,切换到DataMember(正如我之前应该做的那样,或者使用不同的序列化程序)会改变隐含的字母顺序,然后我的大多数字段将不会像众所周知的那样进行反序列化。

我尝试手动添加一个与磁盘上的排序一致的排序(通过属性上的Order属性),但这似乎也没有得到遵守。(我在原始xml中也看不到可以匹配的订单值。)

除了编写一些东西来加载xml并插入缺失的节点之外,还有其他选择吗?(或者等效地设置一个并行类型并从一个反序列化到另一个?)如果不是,我可能只加载当前类型并反序列化到JsonNet或protobuf,但我是否缺少DataMember等更简单的东西?

NetDataContractSerializer使用新属性进行反序列化

[Serializable]标记类型意味着可以通过序列化其公共和私有字段而不是其属性来序列化该类型。NetDataContractSerializer在存在时尊重此属性,按指示序列化字段。对于自动实现的属性,secret backing字段是实际序列化的字段。

当添加一个新字段时,通常处理遗留数据的方法是用[OptionalField]标记它,以表明它不会总是出现在序列化流中。在c#7.3及更高版本中,可以通过使用字段目标属性对自动实现属性的秘密支持字段执行此操作

[Serializable]
public class InheritedClass : BaseClass
{
    public string StringId { get; set; }
    [field: OptionalField]
    public int IntId { get; set; }
}    

在c#7.3之前,无法将属性应用于自动实现属性的backing字段。因此,您需要使backing字段显式,并为其添加属性:

[Serializable]
public class InheritedClass : BaseClass
{
    public string StringId { get; set; }
    [OptionalField]
    int intId;
    public int IntId { get { return intId; } set { intId = value; } }
}    

注:

  • 如问题中所述,如果类型标记有数据协定属性,则NetDataContractSerializer将优先使用默认[Serializable]协定的属性,并允许您显式指示要序列化的属性(并提供比秘密支持字段名称更清晰的名称)。

    不幸的是,向遗留类型添加数据契约属性并不总是实用的。

  • NetDataContractSerializer尚未移植到.NET Core/.NET 5,可能永远不会移植到.