简体   繁体   中英

How to serialize the class which contains dictionary?

I have the following class:

[Serializable]
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Dictionary<string, string> Attributes { get; set; }
}

I would like to serialize it using XmlSerializer and get the following output:

<Person>
    <FirstName>John</FirstName>
    <LastName>Doe</LastName>
    <Attributes>
        <PhoneNumber>12345</PhoneNumber>
        <StreetName>...</StreetName>
        <StreetNumber>...</StreetNumber>
        ...
    </Attributes>
</Person>

Any help would be appreciated.

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

        namespace CSharpSampleApplication.Data.CoreObjects
        {
            [XmlRoot("dictionary")]
            public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
            {

                #region IXmlSerializable Members
                public System.Xml.Schema.XmlSchema GetSchema()
                {
                    return null;
                }

                public void ReadXml(System.Xml.XmlReader reader)
                {
                    XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
                    XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
                    bool wasEmpty = reader.IsEmptyElement;
                    reader.Read();
                    if (wasEmpty)
                        return;



                    while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
                    {
                        reader.ReadStartElement("item");
                        reader.ReadStartElement("key");
                        TKey key = (TKey)keySerializer.Deserialize(reader);
                        reader.ReadEndElement();
                        reader.ReadStartElement("value");
                        TValue value = (TValue)valueSerializer.Deserialize(reader);
                        reader.ReadEndElement();
                        this.Add(key, value);
                        reader.ReadEndElement();
                        reader.MoveToContent();
                    }
                    reader.ReadEndElement();

                }



                public void WriteXml(System.Xml.XmlWriter writer)
                {

                    XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
                    XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
                    foreach (TKey key in this.Keys)
                    {
                        writer.WriteStartElement("item");
                        writer.WriteStartElement("key");
                        keySerializer.Serialize(writer, key);
                        writer.WriteEndElement();
                        writer.WriteStartElement("value");
                        TValue value = this[key];
                        valueSerializer.Serialize(writer, value);
                        writer.WriteEndElement();
                        writer.WriteEndElement();
                    }
                }

                #endregion

            }
        }

Similar to MrFox's answer, this is a hack I've used in the past that works good enough.

public class Foo{

     [XmlIgnore()]
     public Dictionary<string,string> Dct{get;set;}

     [XmlAttribute]
     public string SerializedDictionary{
          get{
               StringBuilder s = new StringBuilder();
               foreach(var kvp in Dct){
                    if (s.Length > 0) s.Append("|");
                    s.AppendFormat("{0},{1}", kvp.Key, kvp.Value);
               }
               return s.ToString();
          }
          set{
               string[] aKvps = value.Split('|');
               Dct = new Dictionary<string,string>();
               for(int i=0; i<aKvps.Length; ++i){
                    string aPair = aKvps[i].Split(',');
                    if (aPair.Length == 2)
                         Dct.Add(aPair[0], aPair[1]);
               }
          }
     }

}

I typed this up from memory and didn't try to compile it, so there may be a bug or two. But hopefully it gets the idea across. Also, this assumes that your data will not have a comma or a pipe in either the keys of the values. If that's the case, this solution may not work for you.

I've done this before:

    /// <summary>
    /// Save all information needed set current game state into given file.
    /// </summary>
    /// <param name="fileName"></param>
    public void save(string fileName)
    {
   Dictionary<string, string> attributes = new Dictionary<string, string>();
   attributes.Add("blue", "very");
   attributes.Add("red", "not");

        Stream stream = File.Open(fileName, FileMode.Create);
        BinaryFormatter bFormatter = new BinaryFormatter();

        // Request the current state of all registered
 // objects and save them into the file.
   foreach (KeyValuePair<string, string> storeOnDisk in attributes)
    bFormatter.Serialize(stream, storeOnDisk);

        stream.Close();
    }

Why don't you use ProtocolBuffer to serialize. It is opensource and free plataform, you can use it with Java, C++ and Python. It's a tip.

As its not possible to serialize a dictionary in dotnet. My Solution is this:

Output:

**<Person>
  <FirstName>John</FirstName>
  <LastName>Doe</LastName>
  <Attributes>
    <PhoneNumber>12345</PhoneNumber>
    <StreetName>StackOverFlow Street</StreetName>
    <StreetNumber>51</StreetNumber>
  </Attributes>
</Person>**

Core Code

public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Dictionary<string, string> Attributes { get; set; }
    }

    public class DictionarySerializer
    {
        private StringBuilder _sBuilder;
        private XmlWriterSettings _writerSettings;
        private XmlWriter w;

        public string WriteXml(Person personObject)
        {
            _sBuilder = new StringBuilder();
            _writerSettings = new XmlWriterSettings();

            _writerSettings.Indent = true;
            _writerSettings.OmitXmlDeclaration = true;
            w = XmlWriter.Create(_sBuilder, _writerSettings);

            //if you remove person properties any dictionary can be turned into XML.
            w.WriteStartElement("Person");           
            w.WriteElementString("FirstName", personObject.FirstName);
            w.WriteElementString("LastName", personObject.LastName);
            w.WriteStartElement("Attributes");

            foreach (var item in personObject.Attributes)
            {
                w.WriteElementString(item.Key, item.Value);
            }

            w.WriteEndElement();
            w.WriteEndElement();
            w.Close();

            return _sBuilder.ToString();
        }
    }

Usage Code

 public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Person objP = new Person();
            objP.FirstName = "John";
            objP.LastName = "Doe";

            objP.Attributes = new Dictionary<string, string>();

            objP.Attributes.Add("PhoneNumber", "12345");
            objP.Attributes.Add("StreetName", "StackOverFlow Street");
            objP.Attributes.Add("StreetNumber", "51");

            DictionarySerializer ds = new DictionarySerializer();
            string val = ds.WriteXml(objP);
        }
    }

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