如何序列化C# Dictionary<int, string>
?
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.
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.
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;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.