为什么在.NET中没有XML序列化字典?

我需要一个XML序列化的字典。 其实我现在有两个不同的程序需要一个。 我很惊讶地看到.NET没有。 我在别处问了这个问题,得到了讽刺的回应。 我不明白为什么这是一个愚蠢的问题。

有人可以启发我,因为如何依赖各种.NETfunction在XML序列化,为什么没有XML序列化字典。 希望你也可以解释为什么有些人认为这是一个愚蠢的问题。 我想我必须错过一些基本的东西,我希望你能填补空白。

关于XML序列化的一点是,它不仅仅是创build一个字节stream。 这也是关于创build这个字节stream将被validation的XML模式。 XML Schema没有很好的方法来表示字典。 你能做的最好的事情就是certificate有一个独特的钥匙。

你总是可以创build自己的包装,例如“字典序列化的一种方法” 。

我知道这已经被回答了,但是因为我用DataContractSerializer类(由WCF使用,但可以并且应该在任何地方使用)做IDictionary序列化的方式非常简洁(代码),我忍不住在这里提供:

 public static class SerializationExtensions { public static string Serialize<T>(this T obj) { var serializer = new DataContractSerializer(obj.GetType()); using (var writer = new StringWriter()) using (var stm = new XmlTextWriter(writer)) { serializer.WriteObject(stm, obj); return writer.ToString(); } } public static T Deserialize<T>(this string serialized) { var serializer = new DataContractSerializer(typeof(T)); using (var reader = new StringReader(serialized)) using (var stm = new XmlTextReader(reader)) { return (T)serializer.ReadObject(stm); } } } 

这在.NET 4中完美工作,也应该在.NET 3.5中工作,尽pipe我还没有testing它。

更新:因为支持DataContractSerializer所以在.NET Compact Framework中不起作用(即使是Windows Phone 7的NETCF 3.7也不行)!

我做串stream是因为它对我来说更方便,尽pipe我可以将更低级别的序列化引入Stream,然后用它来序列化为string,但是我倾向于只在需要时进行概括(就像过早的优化是邪恶的,所以这是过早的泛化…)

用法很简单:

 // dictionary to serialize to string Dictionary<string, object> myDict = new Dictionary<string, object>(); // add items to the dictionary... myDict.Add(...); // serialization is straight-forward string serialized = myDict.Serialize(); ... // deserialization is just as simple Dictionary<string, object> myDictCopy = serialized.Deserialize<Dictionary<string,object>>(); 

myDictCopy将是myDict的逐字拷贝。

您还会注意到,所提供的generics方法将能够序列化任何types(据我所知),因为它不限于IDictionary接口,它可以是任何genericstypesT.

希望它能帮助那里的人!

他们在.NET 3.0中添加了一个。 如果可以,请添加对System.Runtime.Serialization的引用,然后查找System.Xml.XmlDictionary,System.Xml.XmlDictionaryReader和System.Xml.XmlDictionaryWriter。

我同意,这不是一个特别可以发现的地方。

使用DataContractSerializer! 请参阅下面的示例。

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; using System.Xml; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { A a = new A(); a.Value = 1; B b = new B(); b.Value = "SomeValue"; Dictionary<A, B> d = new Dictionary<A,B>(); d.Add(a, b); DataContractSerializer dcs = new DataContractSerializer(typeof(Dictionary<A, B>)); StringBuilder sb = new StringBuilder(); using (XmlWriter xw = XmlWriter.Create(sb)) { dcs.WriteObject(xw, d); } string xml = sb.ToString(); } } public class A { public int Value { get; set; } } public class B { public string Value { get; set; } } } 

上面的代码产生下面的xml:

 <?xml version="1.0" encoding="utf-16"?> <ArrayOfKeyValueOfABHtQdUIlS xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> <KeyValueOfABHtQdUIlS> <Key xmlns:d3p1="http://schemas.datacontract.org/2004/07/ConsoleApplication1"> <d3p1:Value>1</d3p1:Value> </Key> <Value xmlns:d3p1="http://schemas.datacontract.org/2004/07/ConsoleApplication1"> <d3p1:Value>SomeValue</d3p1:Value> </Value> </KeyValueOfABHtQdUIlS> </ArrayOfKeyValueOfABHtQdUIlS> 

创build一个你自己的:-),只读function是奖金,但如果你需要一个string以外的密钥然后该类需要一些修改…

 namespace MyNameSpace { [XmlRoot("SerializableDictionary")] public class SerializableDictionary : Dictionary<String, Object>, IXmlSerializable { internal Boolean _ReadOnly = false; public Boolean ReadOnly { get { return this._ReadOnly; } set { this.CheckReadOnly(); this._ReadOnly = value; } } public new Object this[String key] { get { Object value; return this.TryGetValue(key, out value) ? value : null; } set { this.CheckReadOnly(); if(value != null) { base[key] = value; } else { this.Remove(key); } } } internal void CheckReadOnly() { if(this._ReadOnly) { throw new Exception("Collection is read only"); } } public new void Clear() { this.CheckReadOnly(); base.Clear(); } public new void Add(String key, Object value) { this.CheckReadOnly(); base.Add(key, value); } public new void Remove(String key) { this.CheckReadOnly(); base.Remove(key); } public XmlSchema GetSchema() { return null; } public void ReadXml(XmlReader reader) { Boolean wasEmpty = reader.IsEmptyElement; reader.Read(); if(wasEmpty) { return; } while(reader.NodeType != XmlNodeType.EndElement) { if(reader.Name == "Item") { String key = reader.GetAttribute("Key"); Type type = Type.GetType(reader.GetAttribute("TypeName")); reader.Read(); if(type != null) { this.Add(key, new XmlSerializer(type).Deserialize(reader)); } else { reader.Skip(); } reader.ReadEndElement(); reader.MoveToContent(); } else { reader.ReadToFollowing("Item"); } reader.ReadEndElement(); } public void WriteXml(XmlWriter writer) { foreach(KeyValuePair<String, Object> item in this) { writer.WriteStartElement("Item"); writer.WriteAttributeString("Key", item.Key); writer.WriteAttributeString("TypeName", item.Value.GetType().AssemblyQualifiedName); new XmlSerializer(item.Value.GetType()).Serialize(writer, item.Value); writer.WriteEndElement(); } } } } 

这是我的实现。

 using System; using System.Collections.Generic; using System.Text; using System.Xml.Serialization; using System.Xml.Schema; using System.Xml; namespace Rubik.Staging { [XmlSchemaProvider("GetInternalSchema")] public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable { #region IXmlSerializable Members private const string ns = "http://www.rubik.com.tr/staging"; public static XmlQualifiedName GetInternalSchema(XmlSchemaSet xs) { bool keyIsSimple = (typeof(TKey).IsPrimitive || typeof(TKey) == typeof(string)); bool valueIsSimple = (typeof(TValue).IsPrimitive || typeof(TValue) == typeof(string)); XmlSchemas schemas = new XmlSchemas(); XmlReflectionImporter importer = new XmlReflectionImporter(ns); importer.IncludeType(typeof(TKey)); importer.IncludeType(typeof(TValue)); XmlTypeMapping keyMapping = importer.ImportTypeMapping(typeof(TKey)); XmlTypeMapping valueMapping = importer.ImportTypeMapping(typeof(TValue)); XmlSchemaExporter exporter = new XmlSchemaExporter(schemas); if(!keyIsSimple) exporter.ExportTypeMapping(keyMapping); if(!valueIsSimple) exporter.ExportTypeMapping(valueMapping); XmlSchema schema = (schemas.Count == 0 ? new XmlSchema() : schemas[0]); schema.TargetNamespace = ns; XmlSchemaComplexType type = new XmlSchemaComplexType(); type.Name = "DictionaryOf" + keyMapping.XsdTypeName + "And" + valueMapping.XsdTypeName; XmlSchemaSequence sequence = new XmlSchemaSequence(); XmlSchemaElement item = new XmlSchemaElement(); item.Name = "Item"; XmlSchemaComplexType itemType = new XmlSchemaComplexType(); XmlSchemaSequence itemSequence = new XmlSchemaSequence(); XmlSchemaElement keyElement = new XmlSchemaElement(); keyElement.Name = "Key"; keyElement.MaxOccurs = 1; keyElement.MinOccurs = 1; XmlSchemaComplexType keyType = new XmlSchemaComplexType(); XmlSchemaSequence keySequence = new XmlSchemaSequence(); XmlSchemaElement keyValueElement = new XmlSchemaElement(); keyValueElement.Name = keyMapping.ElementName; keyValueElement.SchemaTypeName = new XmlQualifiedName(keyMapping.XsdTypeName, keyMapping.XsdTypeNamespace); keyValueElement.MinOccurs = 1; keyValueElement.MaxOccurs = 1; keySequence.Items.Add(keyValueElement); keyType.Particle = keySequence; keyElement.SchemaType = keyType; itemSequence.Items.Add(keyElement); XmlSchemaElement valueElement = new XmlSchemaElement(); valueElement.Name = "Value"; valueElement.MaxOccurs = 1; valueElement.MinOccurs = 1; XmlSchemaComplexType valueType = new XmlSchemaComplexType(); XmlSchemaSequence valueSequence = new XmlSchemaSequence(); XmlSchemaElement valueValueElement = new XmlSchemaElement(); valueValueElement.Name = valueMapping.ElementName; valueValueElement.SchemaTypeName = new XmlQualifiedName(valueMapping.XsdTypeName, valueMapping.XsdTypeNamespace); valueValueElement.MinOccurs = 1; valueValueElement.MaxOccurs = 1; valueSequence.Items.Add(valueValueElement); valueType.Particle = valueSequence; valueElement.SchemaType = valueType; itemSequence.Items.Add(valueElement); itemType.Particle = itemSequence; item.SchemaType = itemType; sequence.Items.Add(item); type.Particle = sequence; schema.Items.Add(type); xs.XmlResolver = new XmlUrlResolver(); xs.Add(schema); return new XmlQualifiedName(type.Name, ns); } 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 #region IXmlSerializable Members public XmlSchema GetSchema() { return null; } #endregion } } 

快速将IXmlSerializable添加到任何(现有)字典而不使用inheritance的通用帮助器:

 using System.Xml; using System.Xml.Serialization; using System.Collections.Generic; namespace GameSpace { public class XmlSerializerForDictionary { public struct Pair<TKey,TValue> { public TKey Key; public TValue Value; public Pair(KeyValuePair<TKey,TValue> pair) { Key = pair.Key; Value = pair.Value; }//method }//struct public static void WriteXml<TKey,TValue>(XmlWriter writer, IDictionary<TKey,TValue> dict) { var list = new List<Pair<TKey,TValue>>(dict.Count); foreach (var pair in dict) { list.Add(new Pair<TKey,TValue>(pair)); }//foreach var serializer = new XmlSerializer(list.GetType()); serializer.Serialize(writer, list); }//method public static void ReadXml<TKey, TValue>(XmlReader reader, IDictionary<TKey, TValue> dict) { reader.Read(); var serializer = new XmlSerializer(typeof(List<Pair<TKey,TValue>>)); var list = (List<Pair<TKey,TValue>>)serializer.Deserialize(reader); foreach (var pair in list) { dict.Add(pair.Key, pair.Value); }//foreach reader.Read(); }//method }//class }//namespace 

和一个方便的序列化通用字典:

 using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; using System.Collections.Generic; namespace GameSpace { public class SerializableDictionary<TKey,TValue> : Dictionary<TKey,TValue>, IXmlSerializable { public virtual void WriteXml(XmlWriter writer) { XmlSerializerForDictionary.WriteXml(writer, this); }//method public virtual void ReadXml(XmlReader reader) { XmlSerializerForDictionary.ReadXml(reader, this); }//method public virtual XmlSchema GetSchema() { return null; }//method }//class }//namespace 

我知道现在已经这样做了,但这是我的贡献。 我从@Loudenvier和@Jack的解决scheme中取得了很好的成绩,并编写了自己的序列化(对不起,我是英国的)字典课程。

 public class SerialisableDictionary<T1, T2> : Dictionary<T1, T2>, IXmlSerializable { private static DataContractSerializer serializer = new DataContractSerializer(typeof(Dictionary<T1, T2>)); public void WriteXml(XmlWriter writer) { serializer.WriteObject(writer, this); } public void ReadXml(XmlReader reader) { Dictionary<T1, T2> deserialised = (Dictionary<T1, T2>)serializer.ReadObject(reader); foreach(KeyValuePair<T1, T2> kvp in deserialised) { Add(kvp.Key, kvp.Value); } } public XmlSchema GetSchema() { return null; } } 

我喜欢这种方法,因为你不需要明确地序列化或反序列化任何东西,只需通过一个XmlSerializer抽取整个类层次结构,就完成了。