このようにしてIEnumerableをシリアル化できました。
[XmlArray("TRANSACTIONS")]
[XmlArrayItem("TRANSACTION", typeof(Record))]
public IEnumerable<BudgetRecord> Records
{
get
{
foreach(Record br in _budget)
{
yield return br;
}
}
}
ただし、コレクションDictionary<string, RecordCollection>
(RecordCollectionはIEnumerableを実装しています)を含む辞書が必要になったことに気付きました。
どうすればそれを達成できますか?
次のブログ投稿をご覧ください
そしてこれ(英語ではないが、コードは便利です)
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using System;
public static void Serialize(TextWriter writer, IDictionary dictionary)
{
List<Entry> entries = new List<Entry>(dictionary.Count);
foreach (object key in dictionary.Keys)
{
entries.Add(new Entry(key, dictionary[key]));
}
XmlSerializer serializer = new XmlSerializer(typeof(List<Entry>));
serializer.Serialize(writer, entries);
}
public static void Deserialize(TextReader reader, IDictionary dictionary)
{
dictionary.Clear();
XmlSerializer serializer = new XmlSerializer(typeof(List<Entry>));
List<Entry> list = (List<Entry>)serializer.Deserialize(reader);
foreach (Entry entry in list)
{
dictionary[entry.Key] = entry.Value;
}
}
public class Entry
{
public object Key;
public object Value;
public Entry()
{
}
public Entry(object key, object value)
{
Key = key;
Value = value;
}
}
キーと値が文字列の場合、次のような出力を生成します。
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfEntry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Entry>
<Key xsi:type="xsd:string">MyKey</Key>
<Value xsi:type="xsd:string">MyValue</Value>
</Entry>
<Entry>
<Key xsi:type="xsd:string">MyOtherKey</Key>
<Value xsi:type="xsd:string">MyOtherValue</Value>
</Entry>
</ArrayOfEntry>
しばらくの間、以下を使用しました。もともとは here から来ています。
namespace SerializeDictionary
{
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
/// <summary>
/// Represents an XML serializable collection of keys and values.
/// </summary>
/// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
/// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
[Serializable]
[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
/// <summary>
/// The default XML tag name for an item.
/// </summary>
private const string DefaultItemTag = "item";
/// <summary>
/// The default XML tag name for a key.
/// </summary>
private const string DefaultKeyTag = "key";
/// <summary>
/// The default XML tag name for a value.
/// </summary>
private const string DefaultValueTag = "value";
/// <summary>
/// The XML serializer for the key type.
/// </summary>
private static readonly XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
/// <summary>
/// The XML serializer for the value type.
/// </summary>
private static readonly XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
/// <summary>
/// Initializes a new instance of the
/// <see cref="SerializableDictionary<TKey, TValue>"/> class.
/// </summary>
public SerializableDictionary()
{
}
/// <summary>
/// Initializes a new instance of the
/// <see cref="SerializableDictionary<TKey, TValue>"/> class.
/// </summary>
/// <param name="info">A
/// <see cref="T:System.Runtime.Serialization.SerializationInfo"/> object
/// containing the information required to serialize the
/// <see cref="T:System.Collections.Generic.Dictionary`2"/>.
/// </param>
/// <param name="context">A
/// <see cref="T:System.Runtime.Serialization.StreamingContext"/> structure
/// containing the source and destination of the serialized stream
/// associated with the
/// <see cref="T:System.Collections.Generic.Dictionary`2"/>.
/// </param>
protected SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
/// <summary>
/// Gets the XML tag name for an item.
/// </summary>
protected virtual string ItemTagName
{
get
{
return DefaultItemTag;
}
}
/// <summary>
/// Gets the XML tag name for a key.
/// </summary>
protected virtual string KeyTagName
{
get
{
return DefaultKeyTag;
}
}
/// <summary>
/// Gets the XML tag name for a value.
/// </summary>
protected virtual string ValueTagName
{
get
{
return DefaultValueTag;
}
}
/// <summary>
/// Gets the XML schema for the XML serialization.
/// </summary>
/// <returns>An XML schema for the serialized object.</returns>
public XmlSchema GetSchema()
{
return null;
}
/// <summary>
/// Deserializes the object from XML.
/// </summary>
/// <param name="reader">The XML representation of the object.</param>
public void ReadXml(XmlReader reader)
{
var wasEmpty = reader.IsEmptyElement;
reader.Read();
if (wasEmpty)
{
return;
}
try
{
while (reader.NodeType != XmlNodeType.EndElement)
{
this.ReadItem(reader);
reader.MoveToContent();
}
}
finally
{
reader.ReadEndElement();
}
}
/// <summary>
/// Serializes this instance to XML.
/// </summary>
/// <param name="writer">The XML writer to serialize to.</param>
public void WriteXml(XmlWriter writer)
{
foreach (var keyValuePair in this)
{
this.WriteItem(writer, keyValuePair);
}
}
/// <summary>
/// Deserializes the dictionary item.
/// </summary>
/// <param name="reader">The XML representation of the object.</param>
private void ReadItem(XmlReader reader)
{
reader.ReadStartElement(this.ItemTagName);
try
{
this.Add(this.ReadKey(reader), this.ReadValue(reader));
}
finally
{
reader.ReadEndElement();
}
}
/// <summary>
/// Deserializes the dictionary item's key.
/// </summary>
/// <param name="reader">The XML representation of the object.</param>
/// <returns>The dictionary item's key.</returns>
private TKey ReadKey(XmlReader reader)
{
reader.ReadStartElement(this.KeyTagName);
try
{
return (TKey)keySerializer.Deserialize(reader);
}
finally
{
reader.ReadEndElement();
}
}
/// <summary>
/// Deserializes the dictionary item's value.
/// </summary>
/// <param name="reader">The XML representation of the object.</param>
/// <returns>The dictionary item's value.</returns>
private TValue ReadValue(XmlReader reader)
{
reader.ReadStartElement(this.ValueTagName);
try
{
return (TValue)valueSerializer.Deserialize(reader);
}
finally
{
reader.ReadEndElement();
}
}
/// <summary>
/// Serializes the dictionary item.
/// </summary>
/// <param name="writer">The XML writer to serialize to.</param>
/// <param name="keyValuePair">The key/value pair.</param>
private void WriteItem(XmlWriter writer, KeyValuePair<TKey, TValue> keyValuePair)
{
writer.WriteStartElement(this.ItemTagName);
try
{
this.WriteKey(writer, keyValuePair.Key);
this.WriteValue(writer, keyValuePair.Value);
}
finally
{
writer.WriteEndElement();
}
}
/// <summary>
/// Serializes the dictionary item's key.
/// </summary>
/// <param name="writer">The XML writer to serialize to.</param>
/// <param name="key">The dictionary item's key.</param>
private void WriteKey(XmlWriter writer, TKey key)
{
writer.WriteStartElement(this.KeyTagName);
try
{
keySerializer.Serialize(writer, key);
}
finally
{
writer.WriteEndElement();
}
}
/// <summary>
/// Serializes the dictionary item's value.
/// </summary>
/// <param name="writer">The XML writer to serialize to.</param>
/// <param name="value">The dictionary item's value.</param>
private void WriteValue(XmlWriter writer, TValue value)
{
writer.WriteStartElement(this.ValueTagName);
try
{
valueSerializer.Serialize(writer, value);
}
finally
{
writer.WriteEndElement();
}
}
}
}
この代替の簡単な方法を試してください:
void Main()
{
var source=
new TestClass()
{
GroupTestTyped=
new Dictionary<string, int> { {"A", 23}, {"B", 40} }
};
using (var writer = XmlWriter.Create("c:\\test1.xml"))
(new XmlSerializer(typeof(TestClass))).Serialize(writer, source);
}
[Serializable]
public class DemoElementClass
{
public string Key { get; set; }
public int Value { get; set; }
}
[Serializable]
public class TestClass
{
public TestClass() { }
[XmlArray]
[XmlArrayItem(ElementName = "ElementTest")]
public List<DemoElementClass> GroupTest { get; set; }
[XmlIgnore]
public Dictionary<string, int> GroupTestTyped
{
get { return GroupTest.ToDictionary(x=> x.Key, x => x.Value); }
set { GroupTest = value.Select(x => new DemoElementClass {Key = x.Key, Value = x.Value}).ToList(); }
}
}
Xmlの結果は次のとおりです。
<?xml version="1.0" encoding="utf-8"?>
<TestClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<GroupTest>
<ElementTest>
<Key>A</Key>
<Value>23</Value>
</ElementTest>
<ElementTest>
<Key>B</Key>
<Value>40</Value>
</ElementTest>
</GroupTest>
</TestClass>
Gildorsの回答に基づいた、さらに短いバージョンです。
[XmlElement("Dictionary")]
public List<KeyValuePair<string, string>> XMLDictionaryProxy
{
get
{
return new List<KeyValuePair<string, string>>(this.Dictionary);
}
set
{
this.Dictionary = new Dictionary<string, string>();
foreach (var pair in value)
this.Dictionary[pair.Key] = pair.Value;
}
}
[XmlIgnore]
public Dictionary<string, string> Dictionary
{
get; set;
}
楽しい。