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 :-)
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
- Enumeratori: flags and extensions, il 17 febbraio 2010 alle 23:38
- .NET Framework 4.0 beta 2: Visual Studio 2010, il 19 ottobre 2009 alle 21:23
- .NET Framework 4.0 beta 1: Visual Studio 2010 e Training Kit disponibili per tutti, il 21 maggio 2009 alle 09:25
- .NET Framework 4.0 beta 1: Visual Studio 2010, il 18 maggio 2009 alle 16:39
- L'ordine dei parametri in alcune classi del framework, il 21 agosto 2008 alle 18:47
- The Developer Highway Code, il 19 agosto 2008 alle 14:19