Reputation: 429
How do I serialize a C# Dictionary<int, string>
?
Upvotes: 0
Views: 7028
Reputation: 292445
Assuming you're talking about XML serialization, you could use Paul Welter's SerializableDictionary
class, as suggested by Kevin, but here's another solution, not involving a custom implementation of IXmlSerializable
.
My idea is that a dictionary can be seen as a collection of key-value pairs. XmlSerializer
can serialize a collection, and it can serialize a key-value pair. So you just have to create a wrapper for the dictionary, that appears to be a collection so that XmlSerializer
will handle it without complaining.
Here's my implementation :
A XmlDictionaryEntry
class to hold the key-value pair (the KeyValuePair<TKey, TValue>
class can't be serialized to XML because its properties are read-only)
public class XmlDictionaryEntry<TKey, TValue>
{
public TKey Key { get; set; }
public TValue Value { get; set; }
}
A XmlDictionaryEntryCollection
class, implementing a collection of key-value pairs and using a dictionary to store them
public class XmlDictionaryEntryCollection<TKey, TValue> : ICollection<XmlDictionaryEntry<TKey, TValue>>
{
public XmlDictionaryEntryCollection()
{
this.Dictionary = new Dictionary<TKey, TValue>();
}
public XmlDictionaryEntryCollection(IDictionary<TKey, TValue> dictionary)
{
dictionary.CheckArgumentNull("dictionary");
this.Dictionary = dictionary;
}
[XmlIgnore]
public IDictionary<TKey, TValue> Dictionary { get; private set; }
#region ICollection<XmlDictionaryEntry<TKey,TValue>> Members
public void Add(XmlDictionaryEntry<TKey, TValue> item)
{
this.Dictionary.Add(item.Key, item.Value);
}
public void Clear()
{
this.Dictionary.Clear();
}
public bool Contains(XmlDictionaryEntry<TKey, TValue> item)
{
return this.Dictionary.ContainsKey(item.Key);
}
public void CopyTo(XmlDictionaryEntry<TKey, TValue>[] array, int arrayIndex)
{
int index = arrayIndex;
if (arrayIndex + this.Dictionary.Count > array.Length)
throw new ArgumentException(ExceptionMessages.CopyToNotEnoughSpace);
foreach (var kvp in this.Dictionary)
{
var entry = new XmlDictionaryEntry<TKey, TValue>
{
Key = kvp.Key,
Value = kvp.Value
};
array[index++] = entry;
}
}
public int Count
{
get { return this.Dictionary.Count; }
}
public bool IsReadOnly
{
get { return this.Dictionary.IsReadOnly; }
}
public bool Remove(XmlDictionaryEntry<TKey, TValue> item)
{
return this.Dictionary.Remove(item.Key);
}
#endregion
#region IEnumerable<XmlDictionaryEntry<TKey,TValue>> Members
public IEnumerator<XmlDictionaryEntry<TKey, TValue>> GetEnumerator()
{
foreach (var kvp in this.Dictionary)
{
yield return new XmlDictionaryEntry<TKey, TValue>
{
Key = kvp.Key,
Value = kvp.Value
};
}
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
An extension method to make it easier to create the wrapper (taking advantage of generic type inference) :
public static class XmlSerializationExtension()
{
public static XmlDictionaryEntryCollection<TKey, TValue> AsXmlSerializable<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
{
if (dictionary != null)
return new XmlDictionaryEntryCollection<TKey, TValue>(dictionary);
else
return null;
}
}
Here's how you use it :
Assuming you have this property :
public Dictionary<string, Foo> Foos { get; set; }
You just need to hide that property from the serializer (using the XmlIgnore
attribute), and serialize a XmlDictionaryEntryCollection
instead :
[XmlIgnore]
public Dictionary<string, Foo> Foos { get; set; }
[XmlElement("Foos")]
public XmlDictionaryEntryCollection SerializableFoos
{
get { return Foos.AsXmlSerializable(); }
set { Foos = value.Dictionary; }
}
The main benefit of this technique over the SerializableDictionary
class is that it lets you use any kind of dictionary you want, you're not stuck with a specific implementation.
Upvotes: 1
Reputation: 6050
You can write your own object which has the following two methods, Serialize and DeSerialize. Form_Load is used for testing
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Dictionary<int, string> list = new Dictionary<int, string>();
list.Add(1, "one");
list.Add(2, "two");
list.Add(3, "three");
Dictionary<int, string> list2 = Deserialize(Serialize(list));
}
public string Serialize(Dictionary<int, string> classObject)
{
StringBuilder output = new StringBuilder();
output.Append("<DictionaryIntString>");
foreach (int key in classObject.Keys)
{
output.Append(String.Format("<Key value=\"{0}\">",key));
output.Append(String.Format("<Value>{0}</Value></Key>", classObject[key]));
}
output.Append("</DictionaryIntString>");
return output.ToString();
}
public Dictionary<int, string> Deserialize(string input)
{
Dictionary<int, string> output = new Dictionary<int, string>();
XmlDocument xml = new XmlDocument();
xml.LoadXml(input);
foreach (XmlNode node in xml.GetElementsByTagName("Key"))
{
output.Add(Int32.Parse(node.Attributes["value"].InnerText),node.FirstChild.InnerText);
}
return output;
}
}
Upvotes: 0
Reputation: 273264
Here is a simple demo:
var lookup = new Dictionary<int, string>();
lookup.Add(1, "123");
lookup.Add(2, "456");
using (var ms = new MemoryStream())
{
var formatter =
new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
formatter.Serialize(ms, lookup);
lookup = null;
ms.Position = 0;
lookup = (Dictionary<int, string>) formatter.Deserialize(ms);
}
foreach(var i in lookup.Keys)
{
Console.WriteLine("{0}: {1}", i, lookup[i]);
}
But you probably have to be more specific.
Upvotes: 4