具有新属性的 NetDataContractSerializer 反序列化 [英] NetDataContractSerializer Deserialization With New Property

查看:28
本文介绍了具有新属性的 NetDataContractSerializer 反序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

缺乏真正的远见,我已经使用 NetDataContractSerializer 序列化了大量仅使用 Serializable 修饰的数据,现在我想添加一个新字段.我有哪些选择?

Lacking any real foresight, I've serialized a large set of data decorated only with Serializable using NetDataContractSerializer, and now I'd like to add a new field. What are my options?

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

The original class looks something like this (with a few levels of inheritance and quite a few fields):

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

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

And now I'd like to add another property, say something like:

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

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

Now when I update the class and go to deserialize, I receive an exception since the new field is not present, something like:

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 属性来解决这个问题,例如:

Ok, so this makes sense since NetDataContractSerializer requires the same class. I can get around that using a DataMember attribute like:

[DataMember(IsRequired = false)]

然后的问题是切换到 DataMember(我应该预先完成,或者使用不同的序列化程序)会改变隐式字母顺序,然后我的大多数字段将不会如众所周知的那样静默反序列化.

The problem then is that switching to DataMember (as I should have done upfront, or used a different serializer) changes the implicit alphabetical ordering, and then most of my fields will silently not deserialize as is well known.

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

I've attempted to add an ordering that's inline with the ordering on disk manually (via Order properties on the attribute), but that doesn't appear to be respected either. (I don't see an order value I could match in the raw xml either.)

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

Are there any other options beyond writing something to load the xml and insert the missing node? (Or equivalently setup a parallel type and deserialize from one an re-serialize to another?) If not, I'll probably just load up with the current type and deserialize to JsonNet or protobuf, but am I missing anything more straightforward with DataMember/etc?

推荐答案

[Serializable] 标记一个类型意味着该类型可以通过序列化它的 公共和私有字段——不是它的属性.NetDataContractSerializer 遵守此属性,按指示序列化字段.对于 auto-实现的属性秘密支持字段是实际序列化的内容.

Marking a type with [Serializable] means that the type can be serialized by serializing its public and private fields -- not its properties. NetDataContractSerializer respects this attribute when present, serializing the fields as indicated. For an auto-implemented property the secret backing field is what is actually serialized.

在添加新字段时,处理遗留数据的通常做法是使用 [OptionalField] 表示它不会总是出现在序列化流中.在 c# 7.3 及更高版本中,有可能使用 字段目标属性:

When adding a new field, what one generally does to handle legacy data is to mark it with [OptionalField] to indicate that it won't always be present in serialization streams. In c# 7.3 and later, it's possible to do this to the secret backing field of an auto-implemented property by using a field-targeted attribute:

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

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

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

Prior to c# 7.3 there is no way to apply an attribute to the backing field of an auto-implemented property. Thus you need to make the backing field be explicit and add the attribute to it:

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

    [OptionalField]
    int intId;

    public int IntId { get { return intId; } set { intId = value; } }
}    

注意事项:

  • 如问题中所述,如果类型标记为 数据契约属性 然后 NetDataContractSerializer 将优先使用默认的 [Serializable] 契约并允许您明确指示要序列化的属性(并提供比秘密支持字段名称更清晰的名称).

  • As noted in the question, if a type is marked with data contract attributes then NetDataContractSerializer will use those in preference to the default [Serializable] contract and allow you to explicitly indicate properties to serialize (and provide names clearer than the secret backing field names).

不幸的是,将数据协定属性添加到遗留类型并不总是可行的.

Unfortunately it is not always practical to add data contract attributes to legacy types.

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

这篇关于具有新属性的 NetDataContractSerializer 反序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆