This day, I needed to use XML serialization for a class Dictionary. I was very surprised when I have discovered, that this class does not support this kind of serialization. It seems to be, that XML data format is already the standard today, but it turns out, that is not everywhere. I try to find some solution in Google. I was thinking that somebody has been struggling with the same issue and shared developed solution. I managed to find some examples of solutions to this problem, but each of them had a small errors, that caused, that dictionary did not work as expected.
After a moment of codding, I have managed to get a solution, in which I have not found any errors so far. Below you can find my code, maybe it will useful to somebody. Class SerializableDictionary serializes the object Dictionary formats do binary, as well as to XML.
using System; using System.Runtime.Serialization; using System.Xml; using System.Xml.Serialization; using System.Collections.Generic; using System.Globalization; namespace LicenseCommon { [Serializable] public class SerializableDictionary<TKey, TVal> : Dictionary<TKey, TVal>, IXmlSerializable, ISerializable { #region Private Properties protected XmlSerializer ValueSerializer { get { return _valueSerializer ?? (_valueSerializer = new XmlSerializer(typeof(TVal))); } } private XmlSerializer KeySerializer { get { return _keySerializer ?? (_keySerializer = new XmlSerializer(typeof(TKey))); } } #endregion #region Private Members private XmlSerializer _keySerializer; private XmlSerializer _valueSerializer; #endregion #region Constructors public SerializableDictionary() { } public SerializableDictionary(IDictionary<TKey, TVal> dictionary) : base(dictionary) { } public SerializableDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { } public SerializableDictionary(int capacity) : base(capacity) { } public SerializableDictionary(IDictionary<TKey, TVal> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer) { } public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { } #endregion #region ISerializable Members protected SerializableDictionary(SerializationInfo info, StreamingContext context) { int itemCount = info.GetInt32("itemsCount"); for (int i = 0; i < itemCount; i++) { KeyValuePair<TKey, TVal> kvp = (KeyValuePair<TKey, TVal>)info.GetValue(String.Format(CultureInfo.InvariantCulture, "Item{0}", i), typeof(KeyValuePair<TKey, TVal>)); Add(kvp.Key, kvp.Value); } } void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("itemsCount", Count); int itemIdx = 0; foreach (KeyValuePair<TKey, TVal> kvp in this) { info.AddValue(String.Format(CultureInfo.InvariantCulture, "Item{0}", itemIdx), kvp, typeof(KeyValuePair<TKey, TVal>)); itemIdx++; } } #endregion #region IXmlSerializable Members void IXmlSerializable.WriteXml(XmlWriter writer) { foreach (KeyValuePair<TKey, TVal> kvp in this) { writer.WriteStartElement("item"); writer.WriteStartElement("key"); KeySerializer.Serialize(writer, kvp.Key); writer.WriteEndElement(); writer.WriteStartElement("value"); ValueSerializer.Serialize(writer, kvp.Value); writer.WriteEndElement(); writer.WriteEndElement(); } } void IXmlSerializable.ReadXml(XmlReader reader) { if (reader.IsEmptyElement) { return; } // Move past container if (reader.NodeType == XmlNodeType.Element && !reader.Read()) { throw new XmlException("Error in Deserialization of SerializableDictionary"); } while (reader.NodeType != XmlNodeType.EndElement) { reader.ReadStartElement("item"); reader.ReadStartElement("key"); TKey key = (TKey)KeySerializer.Deserialize(reader); reader.ReadEndElement(); reader.ReadStartElement("value"); TVal value = (TVal)ValueSerializer.Deserialize(reader); reader.ReadEndElement(); reader.ReadEndElement(); Add(key, value); reader.MoveToContent(); } // Move past container if (reader.NodeType == XmlNodeType.EndElement) { reader.ReadEndElement(); } else { throw new XmlException("Error in Deserialization of SerializableDictionary"); } } System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() { return null; } #endregion } }
Two years later, I still haven’t found a way better than this one to serialize a Dictionary in .NET.
Thanks so much!