IDictionary e la serializzazione in XML

di Matteo Casati, in .NET,

Chi lavora con i Web Service si sarà accorto che le strutture chiave/valore (Hashtable, Dictionary generici o specializzati, ecc.), non implementando l'interfaccia IXmlSerializable risultano "intrasportabili".

Qualcuno ci ha anche provato a chiedere a Microsoft di modificare questo comportamento ma la risposta è stata "Won't fix"... La motivazione? Semplice: "Unfortunately, we cannot change Dictionary<K,V> to implement IXmlSerializable since it is located in the mscorlib assembly that cannot reference System.Xml.dll."

In realtà creare un Dictionary generico serializzabile in XML è piuttosto semplice: basta creare una classe "SerializableDictionary" che derivi da Dictionary<TKey, TValue> e implementi IXmlSerializable, serializzando - per ogni KeyValuePair contenuto nella collection di base - sia la chiave che il valore.

Ho fatto due implementazioni: la prima serializza le chiavi e i valori in Base64, la seconda in XML.

KeyValuePair in Base64

using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;

[Serializable]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
#region IXmlSerializable Members

private const string NS = "";
private const string XML_ITEM_NODE_NAME = "item";
private const string XML_KEY_ATTRIBUTE_NAME = "key";
private const string XML_VALUE_ATTRIBUTE_NAME = "value";

public XmlSchema GetSchema()
{
return null;
}

public void WriteXml(XmlWriter w)
{
foreach (TKey key in Keys)
{
TValue value = this[key];
w.WriteStartElement(XML_ITEM_NODE_NAME, NS);
w.WriteElementString(XML_KEY_ATTRIBUTE_NAME, NS, ToBase64(key));
w.WriteElementString(XML_VALUE_ATTRIBUTE_NAME, NS, ToBase64(value));
w.WriteEndElement();
}
}

public void ReadXml(XmlReader r)
{
r.Read();
r.MoveToContent();
while (r.NodeType != XmlNodeType.EndElement)
{
r.ReadStartElement(XML_ITEM_NODE_NAME, NS);
TKey key = FromBase64<TKey>(r.ReadElementString(XML_KEY_ATTRIBUTE_NAME, NS));
TValue value = FromBase64<TValue>(r.ReadElementString(XML_VALUE_ATTRIBUTE_NAME, NS));
r.ReadEndElement();
r.MoveToContent();
Add(key, value);
}
}

#endregion

#region Base64 Serialization

private static string ToBase64(object value)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
formatter.Serialize(stream, value);
byte[] buffer = stream.ToArray();
return Convert.ToBase64String(buffer, 0, buffer.Length, Base64FormattingOptions.None);
}
}

public static T FromBase64<T>(string base64)
{
byte[] buffer = Convert.FromBase64String(base64);
using (MemoryStream stream = new MemoryStream(buffer))
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
return (T)formatter.Deserialize(stream);
}
}

#endregion
}

KeyValuePair in XML

using System;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Collections.Generic;

[Serializable]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
#region IXmlSerializable Members

private const string NS = "";
private const string XML_ITEM_NODE_NAME = "item";
private const string XML_KEY_NODE_NAME = "key";
private const string XML_VALUE_NODE_NAME = "value";

public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
XmlSerializer ks = new XmlSerializer(typeof(TKey));
XmlSerializer vs = new XmlSerializer(typeof(TValue));
bool wasEmpty = reader.IsEmptyElement;
reader.Read();
if (wasEmpty)
return;
while (reader.NodeType != XmlNodeType.EndElement)
{
reader.ReadStartElement(XML_ITEM_NODE_NAME, NS);
reader.ReadStartElement(XML_KEY_NODE_NAME, NS);
TKey key = (TKey)ks.Deserialize(reader);
reader.ReadEndElement();
reader.ReadStartElement(XML_VALUE_NODE_NAME, NS);
TValue value = (TValue)vs.Deserialize(reader);
reader.ReadEndElement();
Add(key, value);
reader.ReadEndElement();
reader.MoveToContent();
}
reader.ReadEndElement();
}

public void WriteXml(XmlWriter writer)
{
XmlSerializer ks = new XmlSerializer(typeof(TKey));
XmlSerializer vs = new XmlSerializer(typeof(TValue));
foreach (TKey key in Keys)
{
writer.WriteStartElement(XML_ITEM_NODE_NAME, NS);
writer.WriteStartElement(XML_KEY_NODE_NAME, NS);
ks.Serialize(writer, key);
writer.WriteEndElement();
writer.WriteStartElement(XML_VALUE_NODE_NAME, NS);
TValue value = this[key];
vs.Serialize(writer, value);
writer.WriteEndElement();
writer.WriteEndElement();
}
}

#endregion
}

 

A voi la scelta :-)

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Nella stessa categoria
I più letti del mese