如何使用 DataContractSerializer 自定义字典序列化?

How to customize dictionary serialization with DataContractSerializer?

使用 DataContractSerializer 的字典序列化生成以下数据。如何用我们自己的属性/标签/标识符替换 d2p1:KeyValueOfintintd2p1:Keyd2p1:Value

序列化 [CashCounter] 中的字典,

下面给出的序列化后生成输出

<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);
}

当序列化为 XML 时,您可以通过继承 Dictionary<TKey, TValue>、应用 CollectionDataContractAttribute 并设置以下属性值来控制字典的项目、键和值元素名称:

  • ItemName: 获取或设置字典 key/value 对元素的自定义名称。

  • KeyName: 获取或设置字典键名元素的自定义名称。

  • ValueName: 获取或设置字典值元素的自定义名称。

  • Namespace:如果需要,获取或设置数据协定的名称空间。

  • Name:如果需要,获取或设置字典类型的数据协定名称。当字典被序列化为根对象时,这将成为 XML 根元素名称。

    (因为字典不是数据模型中的根对象,所以在这种情况下不需要设置这个特定的 属性。)

因此,如果您按如下方式定义 CashCounter 数据模型(已简化以删除不相关的成员):

[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>
{
}

生成的 XML 将如下所示:

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

备注:

  • 您应该考虑用永久的东西替换命名空间。

    命名空间是 data contract name 的一部分。目前它有一些与你的 c# 命名空间相关的默认值,所以如果你重构你的代码并将 类 放入不同的 c# 命名空间,数据协定命名空间可能会改变。由于数据协定命名空间实际上是在您的 WSDL 中发布的,这可能会给您的客户带来麻烦。您可能还希望通过在开头包含您组织的 URL 来将命名空间用于品牌推广。

    如需进一步阅读,请参阅 What does adding Name and Namespace to DataContract do? and What are XML namespaces for?

  • 有关文档,请参阅 Collection Types in Data Contracts: Customizing Dictionary Collections