3

由于缺乏任何真正的远见,我使用 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/ 更直接的东西ETC?

4

1 回答 1

2

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

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

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

    [field: OptionalField]
    public int IntId { get; set; }
}    

在 c# 7.3 之前,无法将属性应用于自动实现属性的支持字段。因此,您需要明确支持字段并向其添加属性:

[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并且可能永远不会移植到 .NET Core/.NET 5 。

于 2015-11-19T23:34:22.813 回答