Custom serialisation of a Dictionary in a DataCont

2019-07-01 11:44发布

问题:

Basically I have a DataContract which contains a Dictionary:

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

    // ...
}

Here is the relevent part of the XML output:

<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>

How can I simplify the output to something like this here:

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

The Dictionary key is restricted to string so if nobody get the stupid idea of using non ascii keys that should work fine. I found the attribute CollectionDataContract with that I come a little bit closer to what I want but the key value pairs will be saved compleate which wasts memory. Maybe it is possible to slove with the class ISerializable but I'm not sure if that makes some trouble with the DataContractSerializer. By the way the solution should also work with the DataContractJsonSerializer.

回答1:

The problem you are having comes from the fact that IDictionary<'string, object> is (in a way) IEnumerable<'KeyValuePair<'string, object>>, and that is way the DataContractSerializer serialize each KeyValuePair individuality.

What you are asking (if I understand correctly) is to create a custom serialization, and for that you can implement the IXmlSerializable interface.

Use the WriteXml, and ReadXml functions to control the xml written to the stream with the XmlWriter passed as parameter.

for example, this function

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

will yield this result

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

assuming two pairs has been entered to the dictionary (ID,15 & Value, 123).

Oh and about the JSON, there is an IJsonSerializable but I never got around to working with it.