DataContractSerializer及其问题 - 搜索更好的序列化程序

时间:2010-08-02 22:00:00

标签: c# xml-serialization .net-4.0

我们已经建立了previously,DCS按字母顺序序列化/反序列化对象。然而,经过进一步调查后,我发现这不是完全真实。

如果我们有这样的结构:

[DataContract]
public class Content
{
    [DataMember]
    public string Title;
    [DataMember]
    public string Slug;
    [DataMember]
    public string Description;
}

[DataContract]
public class TextContent : Content
{
    [DataMember]
    public string Text; 
}

并且有一个TextContent类型的对象要序列化,DCS会这样做:

<Content i:type="TextContent" ...>
<Description>desc</Description>
<Slug>some-slug</Slug>
<Title>content title</Title>
<Text>some content</Text>
</Content>

正如您所看到的,继承类的属性附加到序列化XML片段的末尾,即使它应该在Title之前。 DCS不会检查组合属性并重新排序。 当我在Title元素前面手动添加Text元素时,我注意到了这一点,反序列化只是不想工作。这就是为什么我执行了一个新对象的序列化并想出了这个。

我的问题是:

  1. 这不可能是常识吗?有人注意到了这个吗?
  2. 任何人都知道一个更好的序列化程序(如果我搜索它是旧的XmlSerializer和DCS,我找到的所有内容)因为DCS订购的这个问题非常烦人吗?我知道我们可以使用Order属性,但这只能使我们与一个外部XML源对齐。如果我们有三个,四个或更多第三方XML提供程序,它们都生成完全有效的XML但我们的应用程序对元素顺序的挑剔(因为DCS)会怎样?

3 个答案:

答案 0 :(得分:2)

基本类型始终是订单中的第一个。您可以根据Order属性的DataMember属性定义对象的序列化属性的顺序(请参阅http://msdn.microsoft.com/en-us/library/ms729813.aspx

答案 1 :(得分:0)

NetDataContractSerializer,但它和DCS之间的唯一区别是它支持客户端和服务器之间的类型共享,但是你失去了向前兼容性,因为双方都必须序列化/反序列化为相同的类型。

在codeplex上还有协议缓冲区的C#包装器: http://code.google.com/p/protobuf-net/

我自己没有尝试过,但它应该更快更轻巧。至于你的实际问题:

  1. 怀疑,我当然不会 注意到这个:-P
  2. 你能给出一个实际重要元素排序的例子吗?我自己并没有遇到过这个问题(我猜这就是为什么我们大多数人都没有注意到这种行为......),但是使用proto-buf序列化器这无疑是一个问题..

答案 2 :(得分:0)

如果您需要能够序列化以匹配外部架构,那么您显然不应该使用DataContractSerializer。这不是它的用途。

您可以使用XmlSerializer,旨在让您更好地控制序列化的XML,或实现IXmlSerializable,并获得对XML的完全控制,或者您可以编写自己的自定义使用LINQ to XML进行序列化。这将让您完全按照您的提及 - 以不同方式序列化相同的数据。例如:

数据

internal class Person
{
    internal string Name { get; set; }
    internal string Telephone { get; set; }
    internal Address HomeAddress { get; set; }
    internal Address WorkAddress { get; set; }
}

internal class Address
{
    internal string Line1 { get; set; }
    internal string Line2 { get; set; }
    internal string City { get; set; }
    internal string State { get; set; }
    internal string PostalCode { get; set; }
}

测试计划

private static void Main()
{
    var person = new Person
                     {
                         Name = "John Saunders",
                         Telephone = "something",
                         HomeAddress = new Address
                                           {
                                               Line1 = "Line 1",
                                               Line2 = "Line 2",
                                               City = "SomeCity",
                                               State = "SS",
                                               PostalCode = "99999-9999",
                                           },
                         WorkAddress = new Address
                                           {
                                               Line1 = "Line 1a",
                                               Line2 = "Line 2a",
                                               City = "SomeCitay",
                                               State = "Sa",
                                               PostalCode = "99999-999a",
                                           },
                     };
    XDocument personWithElements = SerializeAsElements(person);
    personWithElements.Save("PersonWithElements.xml");

    XDocument personWithAttributes = SerializeAsAttributes(person);
    personWithAttributes.Save("PersonWithAttributes.xml");
}

序列化为元素:

private static XDocument SerializeAsElements(Person person)
{
    return new XDocument(
        new XElement("Person",
                     new XElement("Name", person.Name),
                     new XElement("Telephone", person.Telephone),
                     SerializeAddressAsElements(person.HomeAddress, "HomeAddress"),
                     SerializeAddressAsElements(person.WorkAddress, "WorkAddress"))
        );
}

private static XElement SerializeAddressAsElements(Address address, string elementName)
{
    return new XElement(elementName,
                        new XElement("Line1", address.Line1),
                        new XElement("Line2", address.Line2),
                        new XElement("City", address.City),
                        new XElement("State", address.State),
                        new XElement("PostalCode", address.PostalCode)
        );
}

序列化为属性:

private static XDocument SerializeAsAttributes(Person person)
{
    return new XDocument(
        new XElement("Person",
                     new XAttribute("Name", person.Name),
                     new XAttribute("Telephone", person.Telephone),
                     SerializeAddressAsAttributes(person.HomeAddress, "HomeAddress"),
                     SerializeAddressAsAttributes(person.WorkAddress, "WorkAddress"))
        );
}

private static XElement SerializeAddressAsAttributes(Address address, string elementName)
{
    return new XElement(elementName,
                        new XAttribute("Line1", address.Line1),
                        new XAttribute("Line2", address.Line2),
                        new XAttribute("City", address.City),
                        new XAttribute("State", address.State),
                        new XAttribute("PostalCode", address.PostalCode)
        );
}

PersonWithElements:

<?xml version="1.0" encoding="utf-8"?>
<Person>
  <Name>John Saunders</Name>
  <Telephone>somethine</Telephone>
  <HomeAddress>
    <Line1>Line 1</Line1>
    <Line2>Line 2</Line2>
    <City>SomeCity</City>
    <State>SS</State>
    <PostalCode>99999-9999</PostalCode>
  </HomeAddress>
  <WorkAddress>
    <Line1>Line 1a</Line1>
    <Line2>Line 2a</Line2>
    <City>SomeCitay</City>
    <State>Sa</State>
    <PostalCode>99999-999a</PostalCode>
  </WorkAddress>
</Person>

PersonWithAttributes:

<?xml version="1.0" encoding="utf-8"?>
<Person Name="John Saunders" Telephone="somethine">
  <HomeAddress Line1="Line 1" Line2="Line 2" City="SomeCity" State="SS" PostalCode="99999-9999" />
  <WorkAddress Line1="Line 1a" Line2="Line 2a" City="SomeCitay" State="Sa" PostalCode="99999-999a" />
</Person>