Navigate / search

SerializableDictionary

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

Comments

avatar
Evan
Reply

Two years later, I still haven’t found a way better than this one to serialize a Dictionary in .NET.

Thanks so much!

Leave a comment

name*

email* (not published)

website