Article written

  • on 20.10.2010
  • at 04:18 PM
  • by Denis

XML сериализация Generic Dictionary 0

Перед разработчиками часто встает задача сохранения Generic Dictionary, в базу данных, файл или просто в памяти. Для того, что бы сохранить данные объекта и иметь возможность быстро восстановить его не зависимо от структуры, первое, что приходит на ум – сериализация. Но проблема в том, что по непонятным причинам даже в .NET 4.0 Generic Dictionary не поддерживают сериализацию. Это я сейчас и исправлю.

Как известно, для того, что бы тип поддерживал сериализацию, необходимо, что бы он реализовывал интерфейс IXmlSerializable. Я предлагаю создать класс SerializableDictionary, который будет реализовывать данный интерфейс.

    [XmlRoot("dictionary")]
    public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
    {
        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader xmlReader)
        {
            XmlSerializer keyXmlSerializer     = new XmlSerializer(typeof(TKey));
            XmlSerializer valueXmlSerializer   = new XmlSerializer(typeof(TValue));

            if (xmlReader.IsEmptyElement)
                return;

            xmlReader.ReadStartElement("root");

            while (xmlReader.NodeType != XmlNodeType.EndElement)
            {
                xmlReader.ReadStartElement("item");
                xmlReader.ReadStartElement("key");

                TKey key = (TKey)keyXmlSerializer.Deserialize(xmlReader);

                xmlReader.ReadEndElement();
                xmlReader.ReadStartElement("value");
                TValue value = (TValue)valueXmlSerializer.Deserialize(xmlReader);
                xmlReader.ReadEndElement();

                this.Add(key, value);
                xmlReader.ReadEndElement();                
            }

            xmlReader.ReadEndElement();
        }

        public SerializableDictionary<TKey, TValue> ReadFromString(string xmlString)
        {
            SerializableDictionary<TKey, TValue> result = null;

            StringReader stringReader = new StringReader(xmlString);
            XmlTextReader xmlTextReader = new XmlTextReader(stringReader);

            ReadXml(xmlTextReader);

            xmlTextReader.Close();
            stringReader.Close();

            return result;
        }

        public void WriteXml(XmlWriter xmlWriter)
        {
            XmlSerializer keyXMLSerializer     = new XmlSerializer(typeof(TKey));
            XmlSerializer valueXMLSerializer   = new XmlSerializer(typeof(TValue));

            foreach (TKey key in this.Keys)
            {
                xmlWriter.WriteStartElement("item");

                xmlWriter.WriteStartElement("key");
                keyXMLSerializer.Serialize(xmlWriter, key);
                xmlWriter.WriteEndElement();

                xmlWriter.WriteStartElement("value");
                TValue value = this[key];
                valueXMLSerializer.Serialize(xmlWriter, value);
                xmlWriter.WriteEndElement();

                xmlWriter.WriteEndElement();
            }
        }        

        public string SerializeToString()
        {
            string result = null;
            MemoryStream memoryStream = new MemoryStream();
            XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
            xmlTextWriter.Namespaces = true;
            
            WriteXml(xmlTextWriter);

            xmlTextWriter.Close();
            memoryStream.Close();

            result = Encoding.UTF8.GetString(memoryStream.GetBuffer());
            result = result.Substring(result.IndexOf(Convert.ToChar(60)));
            result = result.Substring(0, (result.LastIndexOf(Convert.ToChar(62)) + 1));
            result = "<root>" + result + "</root>";

            return result;
        }
    }

Для того, что бы было проще работать с классом, я добавил два метода ReadFromString и SerializeToString. ReadFromString – позволяет создавать объекты из строки, а SerializeToString – сериализует объект в строку. Данные методы упрощают использование объектов типа SerializableDictionary и скрывают от пользователя работу с потоками.

Вот пример использования данного класса:

        static void Main(string[] args)
        {
            SerializableDictionary<string, string> dictionary = new SerializableDictionary<string, string>();
            dictionary.Add("key 1", "value 1");
            dictionary.Add("key 2", "value 2");
            dictionary.Add("key 3", "value 3");

            string stringXML = dictionary.SerializeToString();
            
            SerializableDictionary<string, string> dictionaryOut = new SerializableDictionary<string, string>();
            dictionaryOut.ReadFromString(stringXML);

            foreach (KeyValuePair<string, string> item in dictionaryOut)
                Console.WriteLine("Key: {0}   Value: {1}", item.Key, item.Value);
        }

 

blog comments powered by Disqus

Denis Blog is powered by Drupal
developed by Denis Liger

Valid XHTML 1.0 Strict

Рейтинг@Mail.ru