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