キー/値に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]);
}
}
}
}
DataContractSerializer
クラスでそれができるのかと思っているだけです。出力だけが少し見苦しいです。