我需要一个XML序列化的词典。 其实,我现在有一个需要两个完全不同的程序。 我非常惊讶地看到,.NET没有一个。 我问的问题在其他地方并得到了讽刺的响应。 我不明白为什么这是一个愚蠢的问题。
有人可以告诉我,由于各种.NET功能的依赖程度都在XML序列化,为什么没有一个XML序列化的词典。 希望你也可以解释为什么有些人认为这是一个愚蠢的问题。 我想我必须失去了一些基本的东西,我希望你将能够填补空白。
我需要一个XML序列化的词典。 其实,我现在有一个需要两个完全不同的程序。 我非常惊讶地看到,.NET没有一个。 我问的问题在其他地方并得到了讽刺的响应。 我不明白为什么这是一个愚蠢的问题。
有人可以告诉我,由于各种.NET功能的依赖程度都在XML序列化,为什么没有一个XML序列化的词典。 希望你也可以解释为什么有些人认为这是一个愚蠢的问题。 我想我必须失去了一些基本的东西,我希望你将能够填补空白。
有关XML序列化的事情是,它不只是有关创建字节流。 这也是有关创建一个XML Schema的字节这个流将验证对。 有没有在XML模式没有什么好办法来表示一个字典。 你能做的最好的是要表明,有一个独特的密钥。
你总是可以创建自己的包装,例如单程将序列词典 。
我知道这已经回答过了,但因为我有这样做的IDictionary系列化与DataContractSerializer的类非常简洁的方式(代码)(由WCF使用,但可以而且应该在任何地方使用),我忍不住在这里贡献吧:
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,虽然我没有测试它。
更新:它不会在.NET Compact Framework的工作(不为Windows Phone 7甚至NETCF 3.7)作为DataContractSerializer
是不支持!
我做了流串,因为它是更方便的给我,虽然我可以介绍一个较低级别的序列化流,然后用它来序列化到字符串,但我倾向于在需要的时候只能推广(就像过早的优化是邪恶,所以不宜过早泛化......)
用法很简单:
// 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的完整副本。
您还会注意到,所提供的通用方法将能够系列化任何类型(据我所知),因为它不限于IDictionary的接口,它可以是任何真正的泛型类型T.
希望它可以帮助人在那里!
他们在.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>
创建您自己的:-)之一,只读的特点是奖金,但如果你需要比字符串的密钥等,则类需要一些修改...
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();
}
}
}
}
一个通用的助手快速添加IXmlSerializable的任何(现有的)解释,而不使用继承:
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
这是我的实现。
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
}
}
我知道这已经被做死了,但这里是我的贡献。 我把好位来自@Loudenvier和@Jack的解决方案,并写我自己serialisable(对不起,我是英国人)的字典类。
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;
}
}
我喜欢这种方法,因为你不会有明确连载或deserialise什么,只是泵通过一个XmlSerializer整个类层次,你就大功告成了。