.NET에 XML 직렬화 가능한 사전이없는 이유는 무엇입니까?
XML 직렬화 가능한 사전이 필요합니다. 사실 저는 이제 하나가 필요한 완전히 다른 프로그램이 두 개 있습니다. .NET에 .NET이 없다는 사실에 다소 놀랐습니다. 나는 다른 곳에서 질문하고 비꼬는 반응을 얻었습니다. 왜 어리석은 질문인지 이해가 안 돼요.
다양한 .NET 기능이 XML 직렬화에 얼마나 의존하는지, XML 직렬화 가능한 사전이없는 이유를 감안할 때 누군가 나를 계몽 할 수 있습니까? 바라건대, 왜 일부 사람들이이 질문을 어리석은 질문으로 여기는지 설명 할 수 있습니다. 나는 근본적인 것을 놓치고있는 것 같고 당신이 그 틈새를 메울 수 있기를 바라고 있습니다.
XML 직렬화에 대한 것은 단순히 바이트 스트림을 생성하는 것이 아니라는 것입니다. 또한이 바이트 스트림의 유효성을 검사 할 XML 스키마를 만드는 것입니다. XML 스키마에서 사전을 나타내는 좋은 방법은 없습니다. 할 수있는 최선의 방법은 고유 한 키가 있음을 보여주는 것입니다.
예를 들어 One Way to Serialize Dictionaries와 같이 언제든지 고유 한 래퍼를 만들 수 있습니다 .
나는 이것이 이전에 대답했다는 것을 알고 있지만 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에서도 작동합니다.
업데이트 : 그것은 하지 않습니다 는 다음과 같이 (윈도우 폰 7을위한조차 NETCF 3.7) .NET Compact Framework에서의 작업을 DataContractSerializer
지원하지 않습니다!
나는 Stream에 더 낮은 수준의 직렬화를 도입 한 다음 문자열로 직렬화하는 데 사용할 수 있었지만 더 편리했기 때문에 문자열로 스트리밍을 수행했지만 필요할 때만 일반화하는 경향이 있습니다 (조기 최적화가 악한 것처럼 , 그래서 그것은 조기 일반화입니다 ...)
사용법은 매우 간단합니다.
// 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
}
}
I know this has been done to death now, but here is my contribution. I took the good bits from the solutions from @Loudenvier and @Jack and wrote my own serialisable (sorry, I'm British) dictionary class.
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;
}
}
I like this approach because you won't have to explicitly serialise or deserialise anything, just pump the whole class hierarchy through an XmlSerializer and you're done.
참고URL : https://stackoverflow.com/questions/1124597/why-isnt-there-an-xml-serializable-dictionary-in-net
'IT TIP' 카테고리의 다른 글
.NET Core (비 ASP.NET Core) 프로젝트 용 VS2017 솔루션 탐색기에서 파일을 중첩 할 수 있습니까? (0) | 2020.10.24 |
---|---|
Google Firestore : 속성 값의 하위 문자열에 대한 쿼리 (텍스트 검색) (0) | 2020.10.24 |
사용자 정의 속성의 생성자는 언제 실행됩니까? (0) | 2020.10.24 |
Java : 특정 큐 크기 이후 제출시 차단되는 ExecutorService (0) | 2020.10.24 |
어설 션이 실패 할 때 Python의 unittest에서 계속 (0) | 2020.10.24 |