简体   繁体   中英

How do I serialize a Dictionary<int, string>?

如何序列化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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM