C# - DataContract序列化 - 基类、继承和重写

9
大家好,
我是一名独立游戏开发者,过去主要使用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”进行序列化,那么“Rotation”是否会被正确序列化,并且“Name”会被序列化?
跟进问题: 我本来想早些时候问的,但当时想不起来。 如果属性被覆盖[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]属性是否有任何影响?

你还需要使用KnowType来对typeof(Node)进行FancyNode,因为它是基于XML数据的。 - Jocke
如果您不添加 DataMember,所有的属性都将被视为 DataMember(在 .NET 4 中(我猜测)),但如果您对某些属性进行了设置,则没有设置的属性将不会被序列化。 - Jocke
@L.B 我很乐意尝试,但我认为借鉴他人的经验可能会更有益。不久之后我将需要自己探索实现方法,但如果我能更好地准备,那么可能会节省很多挫败感。 - Nathan Runge
@Jocke 那么你是否必须对类的所有“基类”使用KnowType?我认为你只需要在数据成员可能包含反序列化继承类实例的情况下使用它? - Nathan Runge
取决于您想如何使用类关系,请参见http://msdn.microsoft.com/en-us/library/ms730167.aspx。 - Jocke
4个回答

7

一些回答中提出的思路不够清晰,让我来澄清一下。首先,使用DataContract的序列化器可用于序列化未标记DataContract的类型,您只需要通知序列化器即可。

例如,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可防止属性或字段被序列化。


6
据我所知,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


谢谢,我认为我在使用该框架的其他方面时,可能会使我的研究方向有些偏差。您提供的链接非常有帮助。 - Nathan Runge
示例链接已失效,如果有其他替代链接,那就太好了! - Kit10
我稍后会在回答中更新一些例子(晚饭后!) - Charleh

1

您应该在需要通过契约公开的属性上包含[DataMember]属性。

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

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

请注意,Windows Communication Foundation (WCF) 使用数据契约序列化程序来序列化和反序列化数据(将其转换为 XML 并从 XML 转换回来)。因此,实际上您仍在使用 Xml 序列化。

了解一下WCF的工作原理是很有趣的,感谢您澄清了[DataMember]的问题。在我所做的研究中,有很多相互矛盾的报告。 - Nathan Runge

0

不会进行序列化,因为采用了“Opt-In”方法,你必须明确地给基类应用 DataMember。如果你在子类中继承,数据序列化不会自动工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接