내 이전 문제를 확장하면서 , 나는 잘 작동하는 구성 파일 클래스를 (직렬화)하기로 결정했습니다.
지금은 (값은 네트워크 경로 키가 드라이브 문자) 매핑 및 사용 시도 드라이브 문자 연관 배열을 저장하려는 Dictionary
, HybridDictionary
그리고 Hashtable
이뿐만 호출 할 때 나는 항상 다음과 같은 오류가 ConfigFile.Load()
나 ConfigFile.Save()
:
‘App.ConfigFile’유형을 반영하는 중에 오류가 발생했습니다. [snip] System.NotSupportedException : 멤버 App.Configfile.mappedDrives를 serialize 할 수 없습니다. [snip]
내가 읽은 것에서 사전 및 해시 테이블을 직렬화 할 수 있으므로 내가 뭘 잘못하고 있습니까?
[XmlRoot(ElementName="Config")]
public class ConfigFile
{
public String guiPath { get; set; }
public string configPath { get; set; }
public Dictionary<string, string> mappedDrives = new Dictionary<string, string>();
public Boolean Save(String filename)
{
using(var filestream = File.Open(filename, FileMode.OpenOrCreate,FileAccess.ReadWrite))
{
try
{
var serializer = new XmlSerializer(typeof(ConfigFile));
serializer.Serialize(filestream, this);
return true;
} catch(Exception e) {
MessageBox.Show(e.Message);
return false;
}
}
}
public void addDrive(string drvLetter, string path)
{
this.mappedDrives.Add(drvLetter, path);
}
public static ConfigFile Load(string filename)
{
using (var filestream = File.Open(filename, FileMode.Open, FileAccess.Read))
{
try
{
var serializer = new XmlSerializer(typeof(ConfigFile));
return (ConfigFile)serializer.Deserialize(filestream);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.ToString());
return new ConfigFile();
}
}
}
}
답변
IDictionary를 구현하는 클래스를 직렬화 할 수 없습니다. 이 링크를 확인하십시오 .
Q : 해시 테이블을 직렬화 할 수없는 이유는 무엇입니까?
A : XmlSerializer는 IDictionary 인터페이스를 구현하는 클래스를 처리 할 수 없습니다. 이는 부분적으로 스케줄 제한 사항과 부분적으로 해시 테이블에 XSD 유형 시스템에 대응하는 것이 없기 때문입니다. 유일한 해결책은 IDictionary 인터페이스를 구현하지 않는 사용자 지정 해시 테이블을 구현하는 것입니다.
그래서 당신은 이것을 위해 자신의 사전 버전을 만들어야한다고 생각합니다. 이 다른 질문을 확인하십시오 .
답변
Paul Welter의 Weblog-XML Serializable Generic Dictionary에 솔루션이 있습니다.
어떤 이유로 .net 2.0의 일반 사전은 XML 직렬화 가능하지 않습니다. 다음 코드 스 니펫은 XML 직렬화 가능 일반 사전입니다. IXmlSerializable 인터페이스를 구현하여 사전을 직렬화 할 수 있습니다.
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue>
: Dictionary<TKey, TValue>, IXmlSerializable
{
public SerializableDictionary() { }
public SerializableDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary) { }
public SerializableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer) { }
public SerializableDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { }
public SerializableDictionary(int capacity) : base(capacity) { }
public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { }
#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;
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
}
답변
를 사용하는 대신을 사용할 XmlSerializer
수 있습니다 System.Runtime.Serialization.DataContractSerializer
. 이것은 사전과 인터페이스를 직렬화 할 수 있으며 땀이 나지 않습니다.
다음은 전체 예에 대한 링크입니다. http://theburningmonk.com/2010/05/net-tips-xml-serialize-or-deserialize-dictionary-in-csharp/
답변
직렬화 대리를 만듭니다.
예를 들어, Dictionary 유형의 public 속성을 가진 클래스가 있습니다.
이 유형의 Xml 직렬화를 지원하려면 일반 키-값 클래스를 작성하십시오.
public class SerializeableKeyValue<T1,T2>
{
public T1 Key { get; set; }
public T2 Value { get; set; }
}
XmlIgnore 속성을 원래 속성에 추가하십시오.
[XmlIgnore]
public Dictionary<int, string> SearchCategories { get; set; }
SearchCategories 속성을 직렬화하고 역 직렬화하는 데 사용되는 SerializableKeyValue 인스턴스의 배열을 보유하는 배열 유형의 공용 속성을 노출합니다.
public SerializeableKeyValue<int, string>[] SearchCategoriesSerializable
{
get
{
var list = new List<SerializeableKeyValue<int, string>>();
if (SearchCategories != null)
{
list.AddRange(SearchCategories.Keys.Select(key => new SerializeableKeyValue<int, string>() {Key = key, Value = SearchCategories[key]}));
}
return list.ToArray();
}
set
{
SearchCategories = new Dictionary<int, string>();
foreach (var item in value)
{
SearchCategories.Add( item.Key, item.Value );
}
}
}
답변
사용하기 쉽고 Json.Net을 Dictionary에서 직접 직렬화 해제 할 수있는 Json.Net을 탐색해야합니다.
예:
string json = @"{""key1"":""value1"",""key2"":""value2""}";
Dictionary<string, string> values = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
Console.WriteLine(values.Count);
// 2
Console.WriteLine(values["key1"]);
// value1
답변
사전 및 해시 테이블은로 직렬화 할 수 없습니다 XmlSerializer
. 따라서 직접 사용할 수 없습니다. 해결 방법은 XmlIgnore
속성 을 사용하여 해당 속성을 serializer에서 숨기고 serializable 키-값 쌍 목록을 통해 노출하는 것입니다.
추신 : 구성 XmlSerializer
은 매우 비싸므로 재사용 할 수있는 경우 항상 캐시하십시오.
답변
키 / 값에 xml 특성을 사용하는 SerializableDictionary 클래스를 원했기 때문에 Paul Welter의 클래스를 조정했습니다.
이것은 다음과 같은 xml을 생성합니다.
<Dictionary>
<Item Key="Grass" Value="Green" />
<Item Key="Snow" Value="White" />
<Item Key="Sky" Value="Blue" />
</Dictionary>"
암호:
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
namespace DataTypes {
[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(XmlReader reader) {
XDocument doc = null;
using (XmlReader subtreeReader = reader.ReadSubtree()) {
doc = XDocument.Load(subtreeReader);
}
XmlSerializer serializer = new XmlSerializer(typeof(SerializableKeyValuePair<TKey, TValue>));
foreach (XElement item in doc.Descendants(XName.Get("Item"))) {
using(XmlReader itemReader = item.CreateReader()) {
var kvp = serializer.Deserialize(itemReader) as SerializableKeyValuePair<TKey, TValue>;
this.Add(kvp.Key, kvp.Value);
}
}
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer) {
XmlSerializer serializer = new XmlSerializer(typeof(SerializableKeyValuePair<TKey, TValue>));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
foreach (TKey key in this.Keys) {
TValue value = this[key];
var kvp = new SerializableKeyValuePair<TKey, TValue>(key, value);
serializer.Serialize(writer, kvp, ns);
}
}
#endregion
[XmlRoot("Item")]
public class SerializableKeyValuePair<TKey, TValue> {
[XmlAttribute("Key")]
public TKey Key;
[XmlAttribute("Value")]
public TValue Value;
/// <summary>
/// Default constructor
/// </summary>
public SerializableKeyValuePair() { }
public SerializableKeyValuePair (TKey key, TValue value) {
Key = key;
Value = value;
}
}
}
}
단위 테스트 :
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DataTypes {
[TestClass]
public class SerializableDictionaryTests {
[TestMethod]
public void TestStringStringDict() {
var dict = new SerializableDictionary<string, string>();
dict.Add("Grass", "Green");
dict.Add("Snow", "White");
dict.Add("Sky", "Blue");
dict.Add("Tomato", "Red");
dict.Add("Coal", "Black");
dict.Add("Mud", "Brown");
var serializer = new System.Xml.Serialization.XmlSerializer(dict.GetType());
using (var stream = new MemoryStream()) {
// Load memory stream with this objects xml representation
XmlWriter xmlWriter = null;
try {
xmlWriter = XmlWriter.Create(stream);
serializer.Serialize(xmlWriter, dict);
} finally {
xmlWriter.Close();
}
// Rewind
stream.Seek(0, SeekOrigin.Begin);
XDocument doc = XDocument.Load(stream);
Assert.AreEqual("Dictionary", doc.Root.Name);
Assert.AreEqual(dict.Count, doc.Root.Descendants().Count());
// Rewind
stream.Seek(0, SeekOrigin.Begin);
var outDict = serializer.Deserialize(stream) as SerializableDictionary<string, string>;
Assert.AreEqual(dict["Grass"], outDict["Grass"]);
Assert.AreEqual(dict["Snow"], outDict["Snow"]);
Assert.AreEqual(dict["Sky"], outDict["Sky"]);
}
}
[TestMethod]
public void TestIntIntDict() {
var dict = new SerializableDictionary<int, int>();
dict.Add(4, 7);
dict.Add(5, 9);
dict.Add(7, 8);
var serializer = new System.Xml.Serialization.XmlSerializer(dict.GetType());
using (var stream = new MemoryStream()) {
// Load memory stream with this objects xml representation
XmlWriter xmlWriter = null;
try {
xmlWriter = XmlWriter.Create(stream);
serializer.Serialize(xmlWriter, dict);
} finally {
xmlWriter.Close();
}
// Rewind
stream.Seek(0, SeekOrigin.Begin);
XDocument doc = XDocument.Load(stream);
Assert.AreEqual("Dictionary", doc.Root.Name);
Assert.AreEqual(3, doc.Root.Descendants().Count());
// Rewind
stream.Seek(0, SeekOrigin.Begin);
var outDict = serializer.Deserialize(stream) as SerializableDictionary<int, int>;
Assert.AreEqual(dict[4], outDict[4]);
Assert.AreEqual(dict[5], outDict[5]);
Assert.AreEqual(dict[7], outDict[7]);
}
}
}
}