从.NET源代码我看到Dictionary<TKey,TValue>
实现ISerializable
,因此方法:void GetObjectData(SerializationInfo info, StreamingContext context);
。
在GetObjectData()
看来Comparer
确实已将SerializationInfo
添加为[System.Security.SecurityCritical] // auto-generated_required
public virtual void GetObjectData(SerializationInfo info, StreamingContext context) {
...
info.AddValue(VersionName, version);
#if FEATURE_RANDOMIZED_STRING_HASHING
info.AddValue(ComparerName, HashHelpers.GetEqualityComparerForSerialization(comparer), typeof(IEqualityComparer<TKey>));
#else
info.AddValue(ComparerName, comparer, typeof(IEqualityComparer<TKey>));
#endif
info.AddValue(HashSizeName, buckets == null ? 0 : buckets.Length); //This is the length of the bucket array.
...
}
实例的值,根据MSDN docs; 存储序列化或反序列化对象所需的所有数据:
DataContractSerializer
...但是,实际上,这取决于是使用NetDataContractSerializer
还是using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Text;
namespace ConsoleApplication2
{
public class Program2
{
public static void Main(string[] args)
{
var dict = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
{
{"k", 123}
};
// Prints: "OrdinalComparer"
Console.WriteLine(dict.Comparer.GetType().Name);
// Using DataContractSerializer (DCS)
var dcsXml = SerializeWithDcs(dict);
var dcsDict = DeserializeWithDcs<Dictionary<string, int>>(dcsXml);
// Prints: "GenericEqualityComparer`1"
Console.WriteLine(dcsDict.Comparer.GetType().Name);
// Using NetDataContractSerializer (NetDCS)
var netDcsXml = SerializeWithNetDcs(dict);
var netDcsDict = DeserializeWithNetDcs<Dictionary<string, int>>(netDcsXml);
// Prints: "OrdinalComparer"
Console.WriteLine(netDcsDict.Comparer.GetType().Name);
Console.ReadLine();
}
private static string SerializeWithDcs<T>(T obj)
{
using (var ms = new MemoryStream())
{
using (var sr = new StreamReader(ms, Encoding.UTF8))
{
var serializer = new DataContractSerializer(typeof(T));
serializer.WriteObject(ms, obj);
ms.Position = 0;
return sr.ReadToEnd();
}
}
}
private static T DeserializeWithDcs<T>(string xml)
{
using (var ms = new MemoryStream())
{
using (var sw = new StreamWriter(ms, Encoding.UTF8))
{
sw.Write(xml);
sw.Flush();
ms.Position = 0;
var deserializer = new DataContractSerializer(typeof(T));
return (T)deserializer.ReadObject(ms);
}
}
}
private static string SerializeWithNetDcs(object obj)
{
using (var ms = new MemoryStream())
{
using (var sr = new StreamReader(ms, Encoding.UTF8))
{
var serializer = new NetDataContractSerializer();
serializer.WriteObject(ms, obj);
ms.Position = 0;
return sr.ReadToEnd();
}
}
}
private static T DeserializeWithNetDcs<T>(string xml)
{
using (var ms = new MemoryStream())
{
using (var sw = new StreamWriter(ms, Encoding.UTF8))
{
sw.Write(xml);
sw.Flush();
ms.Position = 0;
var deserializer = new NetDataContractSerializer();
return (T)deserializer.ReadObject(ms);
}
}
}
}
}
。以下是一个完整的例子:
DataContractSerializer
从<ArrayOfKeyValueOfstringint xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<KeyValueOfstringint>
<Key>k</Key>
<Value>123</Value>
</KeyValueOfstringint>
</ArrayOfKeyValueOfstringint>
输出XML:
NetDataContractSerializer
从<ArrayOfKeyValueOfstringint z:Id="1" z:Type="System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]" z:Assembly="0" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Version z:Id="2" z:Type="System.Int32" z:Assembly="0" xmlns="">1</Version>
<Comparer z:Id="3" z:Type="System.OrdinalComparer" z:Assembly="0" xmlns="">
<_ignoreCase xmlns="http://schemas.datacontract.org/2004/07/System">true</_ignoreCase>
</Comparer>
<HashSize z:Id="4" z:Type="System.Int32" z:Assembly="0" xmlns="">3</HashSize>
<KeyValuePairs z:Id="5" z:Type="System.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]][]" z:Assembly="0" z:Size="1" xmlns="">
<KeyValuePairOfstringint xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<key z:Id="6">k</key>
<value>123</value>
</KeyValuePairOfstringint>
</KeyValuePairs>
</ArrayOfKeyValueOfstringint>
输出XML:
Comparer
从XML中可以明显看出,DataContractSerializer
在使用DataContractSerializer
进行序列化/反序列化时已经消失了 - 它根本就不在XML中。
将类型添加到DataContractSerializer
的已知类型中,没有任何区别。
我见过类似的问题(XML serialization of a Dictionary with a custom IEqualityComparer,How do you get WCF serialization to preserve a non-default Comparer on a generic Dictionary?)但据我所知,没有人真正解决这种行为背后的原因,我想理解为什么{{1 }}跳过GetObjectData()
并因此序列化Comparer
?