using System.Collections.Generic;
using System.Xml.Serialization;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Globalization;
using System.ComponentModel.DataAnnotations;
using System.Collections;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
public class SerializableDictionary<TKey, TVal> : Dictionary<TKey, TVal>, IXmlSerializable, ISerializable {
private const string DictionaryNodeName = "Dictionary";
private const string ItemNodeName = "Item";
private const string KeyNodeName = "Key";
private const string ValueNodeName = "Value";
public SerializableDictionary() {
public SerializableDictionary(IDictionary<TKey, TVal> dictionary)
public SerializableDictionary(IEqualityComparer<TKey> comparer)
public SerializableDictionary(int capacity)
public SerializableDictionary(IDictionary<TKey, TVal> dictionary, IEqualityComparer<TKey> comparer)
: base(dictionary, comparer) {
public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer)
: base(capacity, comparer) {
protected SerializableDictionary(SerializationInfo info, StreamingContext context) {
int itemCount = info.GetInt32("ItemCount");
for (int i = 0; i < itemCount; i++) {
KeyValuePair<TKey, TVal> kvp = (KeyValuePair<TKey, TVal>)info.GetValue(String.Format("Item{0}", i), typeof(KeyValuePair<TKey, TVal>));
this.Add(kvp.Key, kvp.Value);
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
info.AddValue("ItemCount", this.Count);
foreach (KeyValuePair<TKey, TVal> kvp in this) {
info.AddValue(String.Format("Item{0}", itemIdx), kvp, typeof(KeyValuePair<TKey, TVal>));
void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) {
foreach (KeyValuePair<TKey, TVal> kvp in this) {
writer.WriteStartElement(ItemNodeName);
writer.WriteStartElement(KeyNodeName);
KeySerializer.Serialize(writer, kvp.Key);
writer.WriteEndElement();
writer.WriteStartElement(ValueNodeName);
ValueSerializer.Serialize(writer, kvp.Value);
writer.WriteEndElement();
writer.WriteEndElement();
void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) {
if (reader.IsEmptyElement) {
throw new XmlException("Error in Deserialization of Dictionary");
while (reader.NodeType != XmlNodeType.EndElement) {
reader.ReadStartElement(ItemNodeName);
reader.ReadStartElement(KeyNodeName);
TKey key = (TKey)KeySerializer.Deserialize(reader);
reader.ReadStartElement(ValueNodeName);
TVal value = (TVal)ValueSerializer.Deserialize(reader);
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() {
protected XmlSerializer ValueSerializer {
if (valueSerializer == null) {
valueSerializer = new XmlSerializer(typeof(TVal));
private XmlSerializer KeySerializer {
if (keySerializer == null) {
keySerializer = new XmlSerializer(typeof(TKey));
private XmlSerializer keySerializer = null;
private XmlSerializer valueSerializer = null;
public static void Test()
var dict = new SerializableDictionary<string, object>()
Console.WriteLine("Serialized dictionary: ");
var dict2 = xml.LoadFromXml<SerializableDictionary<string, object>>();
var xml2 = dict2.GetXml();
Console.WriteLine("Deserialized and re-serialized dictionary: ");
Console.WriteLine("Serialized and re-serialized XML are identical.");
throw new InvalidOperationException("Serialized and re-serialized XML are NOT identical.");
if (Newtonsoft.Json.JsonConvert.SerializeObject(dict) != Newtonsoft.Json.JsonConvert.SerializeObject(dict2))
throw new InvalidOperationException("Newtonsoft.Json.JsonConvert.SerializeObject(dict) != Newtonsoft.Json.JsonConvert.SerializeObject(dict2)");
Console.WriteLine("Original and deserialized dictionaries have identical JSON.");
public static void Main()
public static class XmlSerializationHelper
public static T LoadFromXml<T>(this string xmlString)
using (StringReader reader = new StringReader(xmlString))
return (T)new XmlSerializer(typeof(T)).Deserialize(reader);
public static string GetXml<T>(this T obj, bool omitStandardNamespaces = false)
XmlSerializerNamespaces ns = null;
if (omitStandardNamespaces)
ns = new XmlSerializerNamespaces();
using (var textWriter = new StringWriter())
var settings = new XmlWriterSettings() { Indent = true };
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
new XmlSerializer(obj.GetType()).Serialize(xmlWriter, obj, ns);
return textWriter.ToString();