Как сериализовать класс, который содержит словарь? - PullRequest
3 голосов
/ 11 ноября 2010

У меня есть следующий класс:

[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 ]

2 голосов
/ 11 ноября 2010

Как и в ответе MrFox, этот хак, который я использовал в прошлом, работает достаточно хорошо.

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

}

Я напечатал это из памяти и не пытался скомпилировать, так что может быть одна или две ошибки. Но, надеюсь, это поможет понять идею. Кроме того, это предполагает, что ваши данные не будут иметь запятую или трубу ни в ключах значений. В таком случае это решение может не сработать.

2 голосов
/ 11 ноября 2010
        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 голос
/ 11 ноября 2010

Я делал это раньше:

    /// <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();
    }
0 голосов
/ 11 ноября 2010

Поскольку невозможно сериализовать словарь в 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);
        }
    }
0 голосов
/ 11 ноября 2010

Почему бы вам не использовать ProtocolBuffer для сериализации. Это открытый исходный код и бесплатный платформ, вы можете использовать его с Java, C ++ и Python. Это совет.

...