DataContractSerializer и его проблемы - поиск лучшего сериализатора - PullRequest
0 голосов
/ 03 августа 2010

Мы уже установили ранее , что 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 не рассматривает объединенные свойства и не переупорядочивает их. Я заметил это, когда вручную добавлял элемент Text перед элементом Title, а десериализация просто не хотела работать. Вот почему я выполнил сериализацию нового объекта и выяснил это.

Мои вопросы:

  1. Это не может быть общеизвестно ?? Кто-нибудь еще заметил это?
  2. Кто-нибудь знает о лучшем сериализаторе (все, что я когда-либо нахожу при поиске, это старый XmlSerializer и DCS), потому что эта проблема с упорядочением DCS очень раздражает? Я знаю, что мы можем использовать атрибут Order, но это позволяет нам выравниваться только с одним внешним источником XML. Что если у нас есть три, четыре или более сторонних поставщиков XML, которые все генерируют совершенно корректный XML, но наше приложение придирчиво относится к порядку элементов (из-за DCS)?

Ответы [ 3 ]

2 голосов
/ 03 августа 2010

Базовые типы всегда первые в заказе. Вы можете определить порядок сериализованных свойств объекта с учетом свойства Order атрибута DataMember (см. http://msdn.microsoft.com/en-us/library/ms729813.aspx)

0 голосов
/ 12 августа 2010

Если вам нужно иметь возможность сериализации для соответствия внешней схеме, то вам, очевидно, не следует использовать 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>
0 голосов
/ 03 августа 2010

Существует NetDataContractSerializer , но единственное различие между ним и DCS заключается в том, что он обеспечивает совместное использование типов между клиентом и сервером, но вы теряете прямую совместимость, потому что обе стороны должны сериализовать / десериализовать в одинвведите ..

В кодплексе также есть оболочка C # для буфера протокола: http://code.google.com/p/protobuf-net/

Я сам не пробовал, но она должна быть намного быстрее и легче.Что касается ваших реальных вопросов:

  1. сомневаюсь, я, конечно, никогда не замечал этого :-P
  2. Можете ли вы привести пример, где порядок элементов действительно имел значение?Я сам с этим не сталкивался (наверное, поэтому большинство из нас не замечали такого поведения ...), но с сериализатором proto-buf это, несомненно, будет проблемой ..
...