如何从不使用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 sharpserializer
: Install-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");