自定义XML序列化Dictionary<int, string>

阅读 11.7k
1 个回答

来自@L.B 的答案:

使用临时的item类

public class item
{
    [XmlAttribute]
    public int id;
    [XmlAttribute]
    public string value;
}

示例Dictionary:

Dictionary<int, string> dict = new Dictionary<int, string>()
{
    {1,"one"}, {2,"two"}
};
.
XmlSerializer serializer = new XmlSerializer(typeof(item[]), 
                                 new XmlRootAttribute() { ElementName = "items" });

序列化

serializer.Serialize(stream, 
              dict.Select(kv=>new item(){id = kv.Key,value=kv.Value}).ToArray() );

反序列化

var orgDict = ((item[])serializer.Deserialize(stream))
               .ToDictionary(i => i.id, i => i.value);

这个是使用XElement实现的方法,如果你改变主意的话。
序列化

XElement xElem = new XElement(
                    "items",
                    dict.Select(x => new XElement("item",new XAttribute("id", x.Key),new XAttribute("value", x.Value)))
                 );
var xml = xElem.ToString(); //xElem.Save(...);

反序列化

XElement xElem2 = XElement.Parse(xml); //XElement.Load(...)
var newDict = xElem2.Descendants("item")
                    .ToDictionary(x => (int)x.Attribute("id"), x => (string)x.Attribute("value"));

来自@Scott Chamberlain 的答案:

Paul Welter的 ASP.NET blog有个序列化的dictionary。但是它不使用属性,。我将解释为什么使用如下的代码。

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

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

首先,此代码里有个缺陷,假设你从另一个资源里读到了这样一个dictionary

<dictionary>
  <item>
    <key>
      <string>key1</string>
    </key>
    <value>
      <string>value1</string>
    </value>
  </item>
  <item>
    <key>
      <string>key1</string>
    </key>
    <value>
      <string>value2</string>
    </value>
  </item>
</dictionary>

这将在反序列化时抛出一个异常,因为一个dictionary只能有一个key。
你必须在序列化dictionary使用XElement的原因是:dictionary不是定义为Dictionary<String,String>,而是Dictionary<TKey,TValue>。
为了找出问题,问问你自己:假设我有一个TValue ,使用自我描述为XML的Elements序列化成某个东西,你怎样定义唯一版本的属性,代表完全的内部属性?


来自@manuFS 的回答:

Dictionary在C#里不是默认序列化的,我不知道为什么,但这好像是一个设计的选择。
现在,我建议使用Json.NET转换成JSON,从那里到dictionary(反之亦然)。除非你真的需要XML,不然我见你完全使用JSON。


来自@erikH 的回答:

写一个class A,包含class B阵列,Class B应该有个ID属性和值属性。将XML反序列化成class A,在A中将阵列转换为你想要的dictionary。
为了序列化dictionary,将其转换为class A的实例,然后再序列化。


来自@Gregor Primar 的回答:

   /// <summary>
    /// Serializes object to xml file
    /// </summary>
    /// <param name="data"></param>
    /// <param name="filePath"></param>
    public static void SerializeToXML(object data, string filePath)
    {
        System.IO.Stream stream = null;
        try
        {
            stream = System.IO.File.Open(filePath, System.IO.FileMode.Create);
            System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(data.GetType());
            x.Serialize(stream, data);
            stream.Close();
            stream.Dispose();
        }
        catch (Exception ex)
        {
            try
            {
                stream.Close();
                stream.Dispose();
            }
            catch (Exception)
            {
            }
            throw new Exception(ex.Message);
        }
    }

    /// <summary>
    /// Deserializes xml file to object
    /// </summary>
    /// <param name="filePath"></param>
    /// <returns></returns>
    public static object DeSerializeFromXML(string filePath, Type type)
    {
        object data = null;
        System.IO.Stream stream = null;
        try
        {
            stream = System.IO.File.Open(filePath, System.IO.FileMode.Open);
            System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(type);
            //data = x.Deserialize(stream);
            data = x.Deserialize(new System.Xml.XmlTextReader(stream));
            stream.Close();
            stream.Dispose();
        }
        catch (Exception ex)
        {
            try
            {
                stream.Close();
                stream.Dispose();
            }
            catch (Exception)
            {
            }
            throw new Exception(ex.Message);
        }
        return data;
    }
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
logo
Stack Overflow 翻译
子站问答
访问
宣传栏