Zawód.Programista.NET() Profession, passion, appointment – notes about my adventures with. net

31Oct/103

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

Promuj

Comments (3) Trackbacks (0)
  1. Thanks for this! This has helped me serialize other things.

    A few syntax errors:

    protected SerializableDictionary(SerializationInfo info, StreamingContext context)
    {
    int itemCount = info.GetInt32(“itemsCount”);
    for (int in = 0; in < itemCount; in++)
    {
    KeyValuePair KVP = (KeyValuePair)info.GetValue(String.Format(CultureInfo.InvariantCulture, “Item{0}”, in), typeof(KeyValuePair));
    Add(KVP.Key, KVP.Value);
    }
    }

    “in” is now a keyword, so you’ll have to use something else like “i”

    System.Xml.Scheme.XmlSchema IXmlSerializable.GetSchema()
    {
    return null;
    }

    System.Xml.Scheme <– should be Schema

  2. Yes you are right. I didn’t notice that translation plugin also was translating source code. I have changed it and now everything should be correct in other languages than Polish.

  3. Thanks a lot. very good code.


Leave a comment

(required)


*

No trackbacks yet.