Bleiben wir gleich bei den Enums und bauen wir unsere statische Klasse „EnumerationsHelper“ aus dem letzten Beitrag noch ein bisschen aus, um einen Enum aus einen String zu erstellen.
Für was kann man das brauchen? Also ich benötige diese Funktion (oder eine Abart davon) relativ häufig, wenn ich eine XML-Datei in ein Objekt umwandeln will. Im XML steht zum Beispiel folgendes:

<operator>GreaterThan<operator>

Schauen wir uns erst einmal den Quellcode an, wie das ganze am Ende verwendet werden soll:

static void Main(string[] args)
{
	Console.WriteLine(GetOperator("GreaterThan"));
	Console.WriteLine(GetOperator("Maximum"));

	Console.ReadKey();
}

private static Operators GetOperator(string value)
{
	return value.ToEnum<Operators>();
}

nochmal zur Erinnerung die Definition des Enums:

[DefaultValue(Operators.Equals)]
public enum Operators
{
	Equals,
	GreaterThan,
	LowerThan
}

Wir brauchen also eine Extension-Methode für einen String, der daraus einen Enum macht. Den Typ des Enums wollen wir als generischen Parameter übergeben.
Erst einmal ein paar Überlegungen vorweg:

  • Wir brauchen eine Extensionmethode, mit einem generischen Parameter, wobei der generische Parameter ein Enum sein muss. Das könnte vielleicht ein Problem sein.
  • Wenn eine Umwandlung nicht möglich ist, soll der DefaultValue zurück gegeben werden. Dafür haben wir unsere Methode aus dem letzten Beitrag

Alles in allem hört sich das nicht so schwierig an und ehrlich gesagt ist es dann aus nicht.
Fangen wir mit dem ersten Punkt an: Wir erstellen also eine Extension-Methode mit der Einschränkung, dass der Generic nur ein Enum sein darf

public static T ToEnum<T>(this string value) where T : Enum

Schön wär’s wenn es so einfach wäre. Die Fehlermeldung beim Compilieren lautet folgendermaßen:
Die Einschränkung kann nicht die spezielle 'System.Enum'-Klasse sein.
Also brauchen wir eine andere Lösung:
Ein Enum kann niemals null sein. Das heißt, es handelt sich immer um einen struct. Das können aber schon ziemlich viele Typen sein, die da erlaubt werden. Also nehmen wir noch eine Einschränkung dazu: Enum implementiert das Interface IConvertible. Das macht es schon etwas besser. Aber immer noch nicht optimal, denn zum Beispiel für Int32 treffen die beiden Einschränkungen ebenfalls zu.
Es sieht so aus, als ob man zusätzlich auch noch in der Methode selbst den Typ überprüfen muss.
Wir sind jetzt bei folgendem Code:

public static T ToEnum<T>(this string value) where T : struct, IConvertible
{
	if (!typeof(T).IsEnum)
		throw new ArgumentException("T must be an enumerated type");
	...
}

Der Rest ist dann eigentlich eher einfach. Wir versuchen, ob man den String mit TryParse konvertieren kann. Falls ja, geben wir den konvertierten Wert zurück und ansonsten eben den Defaultwert.
Unsere Methode sieht also jetzt so aus:

public static T ToEnum<T>(this string value) where T: struct, IConvertible
{
	if (!typeof(T).IsEnum)
		throw new ArgumentException("T must be an enumerated type");

	T result;
	if (Enum.TryParse(value, out result))
		return result;
	return GetDefaultValue<T>();
}

Ich denke, damit kann man dann schon ganz gut arbeiten