How to customize dictionary serialization with DataContractSerializer?

狂风中的少年 提交于 2020-07-22 22:11:17

问题


Dictionary serialization with DataContractSerializer generate below data. How to replace d2p1:KeyValueOfintint, d2p1:Key and d2p1:Value with our own attributes / tags / identifier.

Serializing Dictionary in [CashCounter],

Output Generate after Serialization given below

<CashCounter xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/DictionarySerlization">
<BankNote xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <d2p1:KeyValueOfintint>
        <d2p1:Key>10</d2p1:Key>
        <d2p1:Value>6</d2p1:Value>
    </d2p1:KeyValueOfintint>
    <d2p1:KeyValueOfintint>
        <d2p1:Key>5</d2p1:Key>
        <d2p1:Value>10</d2p1:Value>
    </d2p1:KeyValueOfintint>
</BankNote>
<TotalCount>16</TotalCount>
<TotalSum>110</TotalSum>
</CashCounter>

static void Main(string[] args) {
        CashCounter cashCounter = addCashCounter();
        string serilizedData = GetXml(cashCounter);
}

private static CashCounter addCashCounter() {
        CashCounter cashCounter = CreateCounter();

        for(var i = 0; i < 6; i++) { cashCounter = incrementCountAmount(cashCounter, 10); }

        for(var i = 0; i < 10; i++) { cashCounter = incrementCountAmount(cashCounter, 5); }

        return cashCounter;
}

private static CashCounter CreateCounter()
{
        var cashCounter = new CashCounter
        {
            BanknotesCount = new Dictionary<int, int>(),
            TotalSum = 0,
            TotalCount = 0
        };
        return cashCounter;
}

private static CashCounter incrementCountAmount(CashCounter cashCounter, int amount){
        const int count = 1;
        cashCounter.TotalCount += count;
        cashCounter.TotalSum += amount * count;
        if (cashCounter.BanknotesCount.ContainsKey(amount))
        {
            cashCounter.BanknotesCount[amount] += count;
        }
        else
        {
            cashCounter.BanknotesCount.Add(amount, count);
        }
        return cashCounter;
}

public static string GetXml<T>(T obj, DataContractSerializer serializer)
{
        using (var textWriter = new StringWriter())
        {
            var settings = new XmlWriterSettings {OmitXmlDeclaration = true,Indent = true, IndentChars = "    " };
            using (var xmlWriter = XmlWriter.Create(textWriter, settings))
            {
                serializer.WriteObject(xmlWriter, obj);
            }
            return textWriter.ToString();
        }
}

public static string GetXml<T>(T obj)
{
        var serializer = new DataContractSerializer(typeof(T));
        return GetXml(obj, serializer);
}

回答1:


You can control the item, key and value element names of a dictionary when serialized to XML by subclassing Dictionary<TKey, TValue>, applying CollectionDataContractAttribute, and setting the following attribute values:

  • ItemName: gets or sets a custom name for a dictionary key/value pair element.

  • KeyName: gets or sets a custom name for a dictionary key name element.

  • ValueName: gets or sets a custom name for a dictionary value element.

  • Namespace: if needed, gets or sets a namespace for the data contract.

  • Name: if needed, gets or sets the data contract name for the dictionary type. This becomes the XML root element name when the dictionary is serialized as the root object.

    (Since the dictionary is not the root object in your data model, setting this particular property is not needed in this case.)

Thus, if you define your CashCounter data model as follows (simplified to remove irrelevant members):

[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/DictionarySerlization")]
public class CashCounter
{
    [DataMember]
    public BankNoteDictionary BankNote { get; set; }
}

[CollectionDataContract(ItemName = "MyItemName", KeyName = "MyKeyName", ValueName = "MyValueName",
    Namespace = "http://schemas.datacontract.org/2004/07/DictionarySerlization")]
public class BankNoteDictionary : Dictionary<int, int>
{
}

The resulting XML will look like:

<CashCounter xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/DictionarySerlization">
  <BankNote>
    <MyItemName>
      <MyKeyName>10</MyKeyName>
      <MyValueName>6</MyValueName>
    </MyItemName>
    <MyItemName>
      <MyKeyName>5</MyKeyName>
      <MyValueName>10</MyValueName>
    </MyItemName>
  </BankNote>
</CashCounter>

Notes:

  • You should consider replacing the namespace with something permanent.

    The namespace is part of the data contract name. Currently it has some default value related to your c# namespace, so if you refactor your code and put classes into different c# namespaces, the data contract namespace might change. Since the data contract namespace is actually published in your WSDL that could be a nuisance for your customers. You may also want to use the namespace for branding purposes by including your organization's URL at the beginning.

    For further reading see What does adding Name and Namespace to DataContract do? and What are XML namespaces for?.

  • For documentation see Collection Types in Data Contracts: Customizing Dictionary Collections.



来源:https://stackoverflow.com/questions/51915801/how-to-customize-dictionary-serialization-with-datacontractserializer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!