如何序列化包含字典的类?

时间:2010-11-11 12:20:53

标签: c# dictionary xmlserializer

我有以下课程:

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

我想使用XmlSerializer对其进行序列化并获得以下输出:

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

任何帮助都将不胜感激。

5 个答案:

答案 0 :(得分:2)

        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

            }
        }

答案 1 :(得分:2)

与MrFox的答案类似,这是我过去使用过的hack,它已经足够好了。

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]);
               }
          }
     }

}

我从内存中输入了这个,并没有尝试编译它,所以可能有一两个bug。但希望它可以解决这个问题。此外,这假设您的数据在值的键中没有逗号或管道。如果是这种情况,此解决方案可能对您不起作用。

答案 2 :(得分:1)

我以前做过这个:

    /// <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();
    }

答案 3 :(得分:0)

为什么不使用Protocol Buffer进行序列化。它是开源和免费平台,您可以将它与Java,C ++和Python一起使用。这是一个提示。

答案 4 :(得分:0)

因为无法在dotnet中序列化字典。我的解决方案是:

输出:

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

核心代码

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();
        }
    }

使用代码

 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);
        }
    }