XmlEnumAttribute extrahieren
Vorwort
Ungefähr gestern früh gegen drei war es, dass ich an die Grenzen des .Net 2.0 XmlSerializers gestoßen bin. Dieser hatte sich vehement der Aufgabe verweigert, eine statische Klasse zu serialisieren, deren Inhalt ich auf der Platte speichern wollte.
(Nicht genug, dass eben diese Klasse auch eine Hashtable beinhaltete, welche allein einen Workaround für die Serialisierung benötigt hätte.)
Also entschloss ich mich, den steinigeren Weg zu gehen und die Klasse von Hand, also per XmlWriter auf die Platte zu jagen, um sie, auf dem umgekehrten Weg, via XmlReader wieder einzulesen.
Das klappte entgegen meiner anfänglichen Erwartungen erstaunlich gut, und vor allem: Einfach (vom Lesen einmal abgesehen) – Ein kleines Hindernis blieb aber doch. Während es vorher noch möglich war, die Klassen und ihre Elemente mit Metadaten zu taggen, um ihnen in der XML-Datei ein entsprechendes Outfit zu verpassen, war dem jetzt nur noch bedingt der Fall: Taggen ja, Outfit nein.
Ein Problem stellte das bezüglich der zu serialisierenden Klasse natürlich nicht dar – Was mir aber ein Bein stellte war, dass die Elemente der Hashtable ihrerseits eine Enumeration umfassten, deren Werte ich via XmlEnumAttribute fröhlich formatiert hatte – irgendwie umsonst. Damit blieb mir die Wahl zwischen “rohem” Wert – namentlich 0, 1, 2 usw. bis zur Oberkante – oder dem internen Namen des Wertes – Dinge wie “Rot”, “Blau”, “Gemüsebrühe” (bzw. “Gemuesebruehe” für die Genießer unter uns) oder was auch immer.
Ersteres ließe sich auf dem Rückweg via einfachem cast der Marke
-
enum Utensil : int {
-
Bürste = 1,
-
Gabel = 2,
-
// …
-
Zahnstocher = 17,
-
}
-
// …
-
string xmlValue = /* … XmlReader … –> */ "17";
-
IrgendeineEnum value = (IrgendeineEnum) Int32.Parse( xmlValue );
zurechtbiegen, und zweiteres wäre auch nicht weiter schwierig wiederherzustellen, unter Zuhilfename der Enum-Funktion Parse à la
-
string xmlValue = /* … XmlReader … –> */ "Zahnstocher";
Logisch aber, dass erstere Art der Speicherung nicht zweckmäßig im Sinne der Verständlichkeit des serialisierten Formates ist (“
Damit stellte sich also die Frage, wie man an das XmlEnum-Attribut eines beliebigen, gegebenen Enumerationswertes herankommt, um dieses zur Serialisierung zu verwenden – und wie man, andersherum, aus eben jenem String wieder den ursprünglichen Enumerationswert erhält. Lange Rede, kurzer Sinn: Hier ist die Lösung.
Lösung
Erhalten des XmlEnum-Attribut eines Enumerationswertes
Ein Wert einer Enumeration heißt in .NET-Sprache Feld. Folglich holen wir uns die Typinformationen der Enumeration und durchwandern alle ihre Felder, bis der Wert des Feldes mit dem gegebenen übereinstimmen. Danach besorgen wir uns die benutzerdefinierten Attribute des Feldes und picken das XmlEnumAttribute heraus.
-
public static XmlEnumAttribute GetXmlEnumAttribute(object value)
-
{
-
Type type = value.GetType();
-
-
// Iterate through all the fields of the class.
-
foreach (FieldInfo field in type.GetFields())
-
{
-
// skip every field that is not of the same value
-
object checkValue = field.GetValue(value);
-
if (!Enum.Equals(checkValue, value)) continue;
-
-
// Find the XmlEnumAttribute and return it
-
foreach (XmlEnumAttribute attr in Attribute.GetCustomAttributes(field))
-
return attr;
-
}
-
-
// return nothing
-
return null;
-
}
Erhalten des Enumerationswertes anhand des XmlEnum-Attributs
Der umgekehrte Weg funktioniert ähnlich: Wir borgen uns die Typinfo, und durchlaufen alle Felder. In jedem Feld sehen wir uns die XmlEnum-Attribute an und finden eventuell das gesuchte. In diesem Fall geben wir den ‘rohen’ Wert des Feldes zurück. Dieser muss letztlich noch in die Enumeration gecastet werden und die Welt ist wieder schön:
-
public static object GetValueFromXmlEnumAttribute(Type enumType, XmlEnumAttribute value)
-
{
-
-
// Iterate through all the fields of the class.
-
foreach (FieldInfo field in type.GetFields())
-
{
-
// Iterate through all the XmlEnumAttributes (that is, find it)
-
foreach (XmlEnumAttribute attr in Attribute.GetCustomAttributes(field))
-
{
-
if (attr.Equals(value)) return field.GetRawConstantValue();
-
}
-
}
-
// return nothing
-
return null;
-
}
Ein Beispiel zur Anwendung
-
enum TestEnum : int
-
{
-
[XmlEnum("-")]
-
Negativ = -1,
-
[XmlEnum("n/a")]
-
Neutral = 0,
-
[XmlEnum("+")]
-
Positiv = 1
-
}
-
-
// …
-
-
XmlEnumAttribute attrib = GetXmlEnumAttribute(TestEnum.Positiv);
-
// attrib.Name == "+"
-
-
// value == TestEnum.Negativ
Und wieder ein Problem weniger.




Hinterlasse eine Antwort