如何使用 DataContractSerializer 自定义字典序列化?
How to customize dictionary serialization with DataContractSerializer?
使用 DataContractSerializer 的字典序列化生成以下数据。如何用我们自己的属性/标签/标识符替换 d2p1:KeyValueOfintint
、d2p1:Key
和 d2p1: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。
使用 DataContractSerializer 的字典序列化生成以下数据。如何用我们自己的属性/标签/标识符替换 d2p1:KeyValueOfintint
、d2p1:Key
和 d2p1: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。