如何从不使用XElement的自定义XML序列化/反序列化到`Dictionary <int,string>`?

有空的Dictionary<int, string>如何用XML中的键和值填充它

 <items> <item id='int_goes_here' value='string_goes_here'/> </items> 

并将其序列化为不使用XElement的XML?

在临时item类的帮助下

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

示例词典:

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

Paul Welter的ASP.NET博客有一个可序列化的字典。 但是它不使用属性。 我将解释为什么在代码下面。

 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; reader.ReadStartElement("item"); while (reader.NodeType != System.Xml.XmlNodeType.EndElement) { 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.MoveToContent(); } reader.ReadEndElement(); } public void WriteXml(System.Xml.XmlWriter writer) { XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue)); writer.WriteStartElement("item"); foreach (TKey key in this.Keys) { 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> <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> 

这将会导致一个例外,因为你只能有一个字典的关键。


你必须在一个序列化字典中使用XElement的原因是字典没有被定义为Dictionary<String,String> ,字典是Dictionary<TKey,TValue>

为了查看问题,请问你的自我:假设我们有一个TValue序列化到使用元素的东西,它将自身描述为XML(可以说字典Dictionary<int,Dictionary<int,string>> (不是那么罕见一个模式,这是一个查找表)),你的属性唯一版本将如何代表一个字典完全属性内?

字典在C#中默认是不可序列化的,我不知道为什么,但它似乎是一个deviseselect。

现在,我build议使用Json.NET将其转换为JSON并从那里转换成字典(反之亦然)。 除非你真的需要XML,否则我build议完全使用JSON。

我有一个结构KeyValuePairSerializable

 [Serializable] public struct KeyValuePairSerializable<K, V> { public KeyValuePairSerializable(KeyValuePair<K, V> pair) { Key = pair.Key; Value = pair.Value; } [XmlAttribute] public K Key { get; set; } [XmlText] public V Value { get; set; } public override string ToString() { return "[" + StringHelper.ToString(Key, "") + ", " + StringHelper.ToString(Value, "") + "]"; } } 

然后, Dictionary属性的XML序列化如下:

 [XmlIgnore] public Dictionary<string, string> Parameters { get; set; } [XmlArray("Parameters")] [XmlArrayItem("Pair")] [DebuggerBrowsable(DebuggerBrowsableState.Never)] // not necessary public KeyValuePairSerializable<string, string>[] ParametersXml { get { return Parameters?.Select(p => new KeyValuePairSerializable<string, string>(p)).ToArray(); } set { Parameters = value?.ToDictionary(i => i.Key, i => i.Value); } } 

只是属性必须是数组,而不是列表。

写一个类A,它包含一个类B的数组。类B应该有一个id属性和一个值属性。 将xml反序列化为类A.将A中的数组转换为想要的字典。

序列化字典将其转换为类A的实例,并序列化…

我使用可序列化的类来进行不同模块之间的WCF通信。 下面是一个用作DataContract的可序列化类的例子。 我的方法是使用LINQ的强大function将字典转换为KeyValuePair <>的开箱即用序列化List <>:

  using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Xml.Serialization; namespace MyFirm.Common.Data { [DataContract] [Serializable] public class SerializableClassX { // since the Dictionary<> class is not serializable, // we convert it to the List<KeyValuePair<>> [XmlIgnore] public Dictionary<string, int> DictionaryX { get { return SerializableList == null ? null : SerializableList.ToDictionary(item => item.Key, item => item.Value); } set { SerializableList = value == null ? null : value.ToList(); } } [DataMember] [XmlArray("SerializableList")] [XmlArrayItem("Pair")] public List<KeyValuePair<string, int>> SerializableList { get; set; } } } 

用法很简单 – 我将一个字典分配给我的数据对象的字典字段 – DictionaryX。 SerializableClassX通过将分配的字典转换为KeyValuePair <>的可序列化的List <>来支持序列化:

  // create my data object SerializableClassX SerializableObj = new SerializableClassX(param); // this will call the DictionaryX.set and convert the ' // new Dictionary into SerializableList SerializableObj.DictionaryX = new Dictionary<string, int> { {"Key1", 1}, {"Key2", 2}, }; 

基于LB的答案。

用法:

 var serializer = new DictionarySerializer<string, string>(); serializer.Serialize("dictionary.xml", _dictionary); _dictionary = _titleDictSerializer.Deserialize("dictionary.xml"); 

通用类:

 public class DictionarySerializer<TKey, TValue> { [XmlType(TypeName = "Item")] public class Item { [XmlAttribute("key")] public TKey Key; [XmlAttribute("value")] public TValue Value; } private XmlSerializer _serializer = new XmlSerializer(typeof(Item[]), new XmlRootAttribute("Dictionary")); public Dictionary<TKey, TValue> Deserialize(string filename) { using (FileStream stream = new FileStream(filename, FileMode.Open)) using (XmlReader reader = XmlReader.Create(stream)) { return ((Item[])_serializer.Deserialize(reader)).ToDictionary(p => p.Key, p => p.Value); } } public void Serialize(string filename, Dictionary<TKey, TValue> dictionary) { using (var writer = new StreamWriter(filename)) { _serializer.Serialize(writer, dictionary.Select(p => new Item() { Key = p.Key, Value = p.Value }).ToArray()); } } } 

您可以使用ExtendedXmlSerializer 。 如果你有一个class级:

 public class TestClass { public Dictionary<int, string> Dictionary { get; set; } } 

并创build这个类的实例:

 var obj = new TestClass { Dictionary = new Dictionary<int, string> { {1, "First"}, {2, "Second"}, {3, "Other"}, } }; 

您可以使用ExtendedXmlSerializer序列化此对象:

 ExtendedXmlSerializer serializer = new ExtendedXmlSerializer(); var xml = serializer.Serialize(obj); 

输出xml将如下所示:

 <TestClass type="Samples.TestClass"> <Dictionary> <Item> <Key>1</Key> <Value>First</Value> </Item> <Item> <Key>2</Key> <Value>Second</Value> </Item> <Item> <Key>3</Key> <Value>Other</Value> </Item> </Dictionary> </TestClass> 

您可以从nuget安装ExtendedXmlSerializer或运行以下命令:

 Install-Package ExtendedXmlSerializer 

这个序列化器也支持自定义序列化。

Sharpeserializer(开源)有一个简单的方法:

http://www.sharpserializer.com/

它可以直接序列化/反序列化字典。

没有必要用任何属性标记对象,也不必在Serialize方法中给出对象types(请参阅这里 )。

通过nuget Install-package sharpserializerInstall-package sharpserializer

那么这很简单:

Hello World (来自官方网站):

 // create fake obj var obj = createFakeObject(); // create instance of sharpSerializer // with standard constructor it serializes to xml var serializer = new SharpSerializer(); // serialize serializer.Serialize(obj, "test.xml"); // deserialize var obj2 = serializer.Deserialize("test.xml");