【问题标题】:c# - DataContract Serialization - Base Classes, Inheritance and Overridesc# - DataContract 序列化 - 基类、继承和覆盖
【发布时间】:2012-06-22 08:48:47
【问题描述】:

大家好,

我是一名独立游戏开发人员,过去主要与 XNA 合作,而在另一个极端,我主要与商业工具集合作。然而,XNA 的范围非常有限,我正在构建一个跨平台抽象层来针对多个平台。

长话短说,我需要比 [Serializable] 更广泛地访问的 xml 序列化,并且有人指出我需要数据契约。我一直在做很多研究,但找不到任何关于系统基础知识的好信息,与继承和覆盖有关。

我的问题的症结是……

[DataContract]
public class Node
{
    private string name;

    public string Name { get { return name; } set { name = value; } }
    public virtual float Rotation { get { return 0f; } set { } }
}

[DataContract]
public class FancyNode : Node
{
    private float rotation;

    public override float Rotation { get { return rotation; } set { rotation = value; } }
}

如果我序列化一个“FancyNode”,是否会正确序列化“旋转”,是否会序列化“名称”?

后续问题: 本来想早点问的,当时想不起来了。序列化程序处理程序如何覆盖 [IgnoreDataMember] 属性?比如……

[DataContract]
public class Simple
{
    [IgnoreDataMember]
    public virtual string Value { get { return ""; } set { } }
}

[DataContract]
public class Complex : Simple
{
    private string value;

    public override string Value { get { return value; } set { this.value = value; } }
}

“复杂”中的“值”会被序列化吗?一些答案表明,如果不使用 [DataMember] 标记,则所有属性都将被序列化。如果有,基类的[IgnoreDataMember]属性有什么关系吗?

【问题讨论】:

  • 你还需要为 typeof(Node) 使用 KnowType 的 FancyNode,因为它是 XML(基于数据的)...
  • 如果你不添加 DataMember,所有的 props 都将被视为 DataMember(在 .NET 4 中(我猜)),但如果你做了一些没有的将不会被序列化。
  • @L.B 我很乐意尝试,但我认为我可能会从其他人的经验中受益。很快我将需要自己探索实现,但如果我能做好准备,可能会减少很多挫折。
  • @Jocke 那么你必须对一个类的所有“基类”使用 KnowType 吗?我的印象是您只需要在数据成员可能包含反序列化继承类实例的情况下使用它?
  • 取决于你想如何使用类关系,见msdn.microsoft.com/en-us/library/ms730167.aspx

标签: c# inheritance serialization overriding datacontract


【解决方案1】:

据我所知,DataContract 是一种“选择加入”的序列化方法,即除非你装饰它(告诉序列化程序你想要序列化它),否则不会序列化东西

因此对于上面的示例,您需要将 [DataMember] 添加到要序列化的属性中

使用标准的 Serializable 属性,序列化程序会查看所有字段并仅忽略您标记为 NonSerialized 的字段

这里有一些例子:

http://jamescbender.azurewebsites.net/?p=651

查看注释部分,了解有关序列化内容的信息以及发生的大致情况:

http://msdn.microsoft.com/en-us/library/ms733127.aspx

编辑:我也看不出任何曾经标记为 [DataMember] 的字段无法正确序列化的任何原因。序列化的 DataContract 方法还可以处理循环引用——其他序列化有时会遇到问题:

http://msdn.microsoft.com/en-us/library/hh241056.aspx

【讨论】:

  • 谢谢,我认为我在框架其他方面的经验稍微偏离了我的研究方向。您提供的链接非常有帮助。
  • 示例链接已失效,如果有人有替代品,那就太好了!
  • 稍后我会用一些例子更新答案(晚餐后!)
【解决方案2】:

一些答案​​中提出的一些想法不清楚。请让我把它们清理干净。首先,使用 DataContract 的序列化器可用于序列化未使用 DataContract 修饰的类型。您只需要通知 serailizer 即可。

例如,DataContractJsonSerializer 类会将一个类型序列化为 JSON 对象(通常是字符串)。您只需要告诉它您要序列化的对象的类型,然后是它可能引用的任何其他类型:

var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(MyClass), new Type[] { Type1, Type2, Type3 });

序列化器会自动序列化该类型的每个公共字段和属性。欲了解更多信息,请参阅http://msdn.microsoft.com/en-us/ms733127

DataContractAttribute 标记类型

使用DataContractAttribute 标记类型后,您将该类型转换为自动已知的类型(您不需要将其作为子类型提供)并将其转换为属性和字段以选择加入模式。

因此,您必须使用DataMemberAttribute 来装饰要序列化的每个字段或属性。这意味着IgnoreDataMemberAttribute 没用。是的,序列化程序不会查找它,因为任何未标记为 DataMemberAttribute 的内容都会被自动忽略。

未标记的 DataContractAttribute 类型

当序列化未应用 DataContractAttribute 的类型时,如前所述,每个公共属性或字段都将被序列化。因此,这里使用IgnoreDataMemberAttribute 来防止某个属性或字段被序列化。

【讨论】:

    【解决方案3】:

    您应该在应由合约公开的属性中包含[DataMember] 属性。

    [DataContract]
    public class FancyNode : Node
    {
        private float rotation;
    
        [DataMember]
        public override float Rotation { get { return rotation; } set { rotation = value; } }
    }
    

    请注意,Windows Communication Foundation (WCF) 使用 Data Contract Serializer 来序列化和反序列化数据(将其转换为 XML 或从 XML 转换)。所以实际上你仍在使用 Xml 序列化。

    【讨论】:

    • 了解更多有关 WCF 工作原理的信息很有趣,感谢您解决 [DataMember] 问题。我所做的研究中有很多相互矛盾的报告。
    【解决方案4】:

    不,由于选择加入方法,它不会序列化,您必须将 DataMember 显式应用于您的基类。如果您在子类中继承,数据序列化不会自动工作

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-23
      • 1970-01-01
      • 1970-01-01
      • 2011-01-10
      • 2011-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多