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;
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
}
まず、このコードには1つの落とし穴があります。これがある別のソースから辞書を読んだとします。
<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>
ディクショナリにはキーを1つしか持てないため、これにより、de-seariazationで例外がスローされます。
seriazedディクショナリでXElementを使用しなければならない理由は、ディクショナリがとして定義されていないためです。Dictionary<String,String>
ディクショナリはDictionary<TKey,TValue>
です。
問題を確認するには、自問してみてくださいTValue
。XMLとして記述されているElementsを使用するものにシリアル化するものがあるとします(辞書の辞書Dictionary<int,Dictionary<int,string>>
(パターンの珍しいことではなく、ルックアップテーブルです))、どのように属性のみのバージョンは、完全に属性内の辞書を表しますか?
辞書はデフォルトではC#でシリアル化できません。理由はわかりませんが、設計上の選択だったようです。
今のところ、Json.NETを使用してJSONに変換し、そこから辞書に変換することをお勧めします(その逆も同様です)。本当にXMLが必要な場合を除いて、JSONを完全に使用することをお勧めします。
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を使用できます。クラスがある場合:
public class TestClass
{
public Dictionary<int, string> Dictionary { get; set; }
}
このクラスのインスタンスを作成します。
var obj = new TestClass
{
Dictionary = new Dictionary<int, string>
{
{1, "First"},
{2, "Second"},
{3, "Other"},
}
};
ExtendedXmlSerializerを使用して、このオブジェクトをシリアル化できます。
var serializer = new ConfigurationContainer()
.UseOptimizedNamespaces() //If you want to have all namespaces in root element
.Create();
var xml = serializer.Serialize(
new XmlWriterSettings { Indent = true }, //If you want to formated xml
obj);
出力xmlは次のようになります。
<?xml version="1.0" encoding="utf-8"?>
<TestClass xmlns:sys="https://extendedxmlserializer.github.io/system" xmlns:exs="https://extendedxmlserializer.github.io/v2" xmlns="clr-namespace:ExtendedXmlSerializer.Samples;assembly=ExtendedXmlSerializer.Samples">
<Dictionary>
<sys:Item>
<Key>1</Key>
<Value>First</Value>
</sys:Item>
<sys:Item>
<Key>2</Key>
<Value>Second</Value>
</sys:Item>
<sys:Item>
<Key>3</Key>
<Value>Other</Value>
</sys:Item>
</Dictionary>
</TestClass>
nugetからExtendedXmlSerializerをインストールするか、次のコマンドを実行できます。
Install-Package ExtendedXmlSerializer
私は構造体を持っています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);
}
}
プロパティだけがリストではなく配列でなければなりません。
クラスBの配列を含むクラスAを記述します。クラスBにはidプロパティとvalueプロパティが必要です。xmlをクラスAに逆シリアル化します。Aの配列を必要な辞書に変換します。
辞書をシリアル化するには、辞書をクラスAのインスタンスに変換し、シリアル化します...
KeyedCollectionは辞書のように機能し、シリアル化できます。
まず、キーと値を含むクラスを作成します。
/// <summary>
/// simple class
/// </summary>
/// <remarks></remarks>
[Serializable()]
public class cCulture
{
/// <summary>
/// culture
/// </summary>
public string culture;
/// <summary>
/// word list
/// </summary>
public List<string> list;
/// <summary>
/// status
/// </summary>
public string status;
}
次に、KeyedCollectionタイプのクラスを作成し、クラスのプロパティをキーとして定義します。
/// <summary>
/// keyed collection.
/// </summary>
/// <remarks></remarks>
[Serializable()]
public class cCultures : System.Collections.ObjectModel.KeyedCollection<string, cCulture>
{
protected override string GetKeyForItem(cCulture item)
{
return item.culture;
}
}
このようなタイプのデータをシリアル化するのに役立ちます。
異なるモジュール間のWCF通信にシリアル化可能なクラスを使用します。以下は、DataContractとしても機能するシリアル化可能なクラスの例です。私のアプローチは、LINQの機能を使用して、辞書をKeyValuePair<>のすぐに使用可能なシリアル化可能なリスト<>に変換することです。
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。シリアル化は、割り当てられたディクショナリをKeyValuePair<>のシリアル化可能なリスト<>に変換することによってSerializableClassX内でサポートされます。
// 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},
};
Sharpeserializer(オープンソース)には簡単な方法があります:
http://www.sharpserializer.com/
辞書を直接シリアル化/逆シリアル化できます。
オブジェクトに属性をマークする必要はありません。また、Serializeメソッドでオブジェクトタイプを指定する必要もありません(ここを参照 )。
nuget経由でインストールするには:Install-package sharpserializer
それからそれは非常に簡単です:
Hello World(公式Webサイトから):
// 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");