Wie versprochen nun die Fortsetzung.
Um "beliebige" Objekte lesen und schreiben zu können, bediene ich mich der Serialisierungmöglichkeiten von .NET. Es werden zwei neue Methoden eingeführt
GetObject<T> und
SetObject<T>. Die Implementierung dieser Methoden sieht dann wie folgt aus.
// <summary>
/// Gets the object.
/// </summary>
/// <param name="node">The node.</param>
/// <returns></returns>
private static T GetObject<T>(XmlNode node)
{
T result = default(T);
//restore object from node
XmlSerializer ser = new XmlSerializer(typeof(T));
result = (T)ser.Deserialize(new StringReader(node.OuterXml));
return result;
}
/// <summary>
/// Sets the object.
/// </summary>
/// <param name="node">The node.</param>
/// <param name="value">The value.</param>
private static void SetObject<T>(XmlNode node, T value)
{
if(value == null)
{
return;
}
using(MemoryStream stream = new MemoryStream())
{
//serialize object
XmlSerializer ser = new XmlSerializer(typeof(T));
ser.Serialize(stream, value);
//reset read position
stream.Position = 0;
XmlElement newNode = null;
using(XmlReader reader = XmlReader.Create(stream))
{
//move to the content node.
reader.MoveToContent();
//create new element in node context
newNode = node.OwnerDocument.CreateElement(reader.Name);
//set content
newNode.InnerXml = reader.ReadInnerXml();
}
//append the new node
node.AppendChild(newNode);
}
}
Die beiden Methoden können natürlich auch
public gemacht werden, damit sie explizit aufgerufen werden können. Diese Variante ist im Falle einer reinen Hilfsklasse für unterschiedlichste Projekte in der Tat auch vorzuziehen, da es die Verwendungsmöglichkeiten besser hervorhebt.
Im konkreten Beispiel habe ich sie einfach als zusätzlichen Aufruf in die Methoden
SetValue<T> und
GetValue<T> eingebaut. Irgendwie muß ich ja mein Versprechen erfüllen, mich von der IConvertible-Schnittstelle zu trennen. Nun noch kurz die geänderten Bereiche obiger Methoden, dann sollte ich meiner Verpflichtung nachgekommen sein.

public static T GetValue<T>(XmlNode node, T @default)
{
...
if(!IsConvertible(typeof(T)))
{
//get complex object
result = GetObject<T>(node);
result = result != null ? result : @default;
}
else
{
...
}
...
}
public static void SetValue<T>(XmlNode node, T value)
{
...
if(!IsConvertible(typeof(T)))
{
SetObject<T>(node, value);
return;
}
...
}
Diese Lösung ist ganz klar ein erster Ansatz. Sie weist in dieser Ausprägung noch einige Lücken auf, welche ich nicht verschweigen möchte.
- Das Löschen von Objektknoten ist in dieser Variante nicht möglich
- Das Setzen eines komplexen Objektes führt immer zu einem anfügen. Durch die nicht vorhandene Objektidentität wird bei mehrfachen Aufrufen das Objekt auch mehrfach hinzugefügt.
- Das unterschiedliche Verhalten von Lesen und Schreiben kann zu Irritationen führen.
- Die XML-Serialisierung kann unter Umständen nicht erfolgreich sein, was dann einige Anforderungen an die Klassen stellt, um dies dennoch zu ermöglichen.