Пользовательская сериализация словаря в DataContract

В основном у меня есть DataContract, который содержит Dictionary:

[DataContract]
public class MyDictionary : IDictionary<string, object> {
    [DataMember(Name = "Data")]
    protected IDictionary<string, object> Dictionary { get; private set; }

    // ...
}

Вот соответствующая часть вывода XML:

<Data>
 <a:KeyValueOfstringanyType>
  <a:Key>ID</a:Key>
  <a:Value i:type="s:int">2</a:Value>
 </a:KeyValueOfstringanyType>
 <a:KeyValueOfstringanyType>
  <a:Key>Value</a:Key>
  <a:Value i:type="s:int">4711</a:Value>
 </a:KeyValueOfstringanyType>
</Data>

Как я могу упростить вывод примерно так:

<Data>
  <ID i:type="s:int">2</ID>
  <Value i:type="s:int">4711</Value>
</Data>

Ключ словаря ограничен строкой, поэтому, если никому не придет в голову глупая идея использовать не ascii-ключи, это должно работать нормально. Я нашел атрибут CollectionDataContract, с которым я немного приближаюсь к тому, что хочу, но пары ключ-значение будут сохранены, что тратит память. Возможно, с классом ISerializable можно работать, но я не уверен, что это создаст проблемы с DataContractSerializer. Кстати, решение должно работать и с DataContractJsonSerializer.


person rekire    schedule 27.06.2012    source источник
comment
Не будет ли это преждевременной оптимизацией, не так ли? Я склонен позволять DataContracts и сериализаторам/десериализаторам делать свое дело, когда это возможно, чтобы избежать головной боли.   -  person Chris Sinclair    schedule 28.06.2012
comment
@ChrisSinclair Может быть много пар ключ-значение, а также этот материал читается клиентом Android в формате JSON. Пока я думаю, что работа должна иметь смысл.   -  person rekire    schedule 28.06.2012
comment
В этом случае вы хотите использовать сериализаторы JSON, а не сериализаторы XML? Если это так, то, возможно, стоит прикрепить к нему сериализатор JSON и увидеть его результат. (возможно, он уже достаточно оптимизирован). Кроме того, если вы хотите сохранить XML, вам, вероятно, потребуется какая-то оболочка Entry вокруг идентификатора/значения, чтобы вы могли иметь несколько пар KeyValuePair. <Data><Entry><ID i:type="s:int">2</ID><Value i:type="s:int">4711</Value></Entry></Data> РЕДАКТИРОВАТЬ: Извините, я не заметил, что ваше последнее предложение хочет, чтобы оно работало как с сериализаторами JSON, так и с XML.   -  person Chris Sinclair    schedule 28.06.2012
comment
@ChrisSinclair Я хочу иметь возможность использовать как XML, так и JSON. JSON тоже не оптимизирован. В чем преимущество использования этих Entrys?   -  person rekire    schedule 28.06.2012
comment
Больше требований XML (возможно, и JSON). Как вы будете сериализовать несколько статей вашего словаря? Я полагаю, вы могли бы сложить их как <Data><ID /><ID /><ID /><Value /><Value /><Value /></Data> и предположить, что они находятся в том же порядке, чтобы правильно связать записи ID с записями Value.   -  person Chris Sinclair    schedule 28.06.2012
comment
В MyDictionary каждый ключ уникален...   -  person rekire    schedule 28.06.2012
comment
Да, и вам придется выражать каждую словарную запись как действительный XML; то, что у вас есть сейчас в качестве желаемого результата, не будет действительным для набора записей. Возможно, вам следует отредактировать свой вопрос, указав, как вы ожидаете, что XML будет выглядеть для нескольких записей (а не только для одной), как в настоящее время выглядит JSON и как вы хотите, чтобы он выглядел вместо этого. Наконец, что вас беспокоит по этому поводу? Вас беспокоит размер передачи данных между сервисами? Если да, то какой размер вы получаете в настоящее время и до чего вы хотите/должны его уменьшить?   -  person Chris Sinclair    schedule 28.06.2012


Ответы (1)


Проблема, с которой вы столкнулись, связана с тем, что IDictionary‹’string, object> является (в некотором роде) IEnumerable’KeyValuePair‹’string, object>>, и таким образом DataContractSerializer сериализует каждую индивидуальность KeyValuePair.

Вы просите (если я правильно понимаю) создать пользовательскую сериализацию, и для этого вы можете реализовать IXmlSerializable.

Используйте функции WriteXml и ReadXml для управления XML-файлом, записываемым в поток с XmlWriter, переданным в качестве параметра.

например, эта функция

public void WriteXml(XmlWriter writer)
    {
        foreach (var pair in _dictionary)
        {
            writer.WriteElementString("Key", pair.Key);
            writer.WriteElementString("Value", pair.Value.ToString());
        }
    }

даст этот результат

<MyDictionary xmlns="http://schemas.datacontract.org/2004/07/Sandbox">
    <Key>ID</Key>
    <Value>15</Value>
    <Key>Value</Key>
    <Value>123</Value>
</MyDictionary>

при условии, что в словарь были введены две пары (ID, 15 и Value, 123).

Да, и насчет JSON, есть IJsonSerializable, но я так и не обошёл к работе с ним.

person Matan Lieberman    schedule 11.05.2013
comment
Неожиданно я получил новую работу и больше не использую WCF, но ваш ответ очень логичен и имеет смысл. Просто для завершения не могли бы вы расширить свой пример того, как должен быть реализован интерфейс IXmlSerializable и как можно использовать этот сериализатор. +1 Пока за вашу работу. - person rekire; 11.05.2013