Among other awesome features introduced in C# 3.0 are amazing extension methods. It looks like taking on board dynamic-language-oriented people like John Lam is starting to pay out for Microsoft. Now this Ruby-style can be done in C#:
42.IsInRange(range);
Woohoo! The feature is quite powerful and if you think about that - a little bit intimidating for a static-language mind. Ruby people will be definitely more comfortable with the idea of such a freedom.
A release earlier - in .NET 2.0 - Microsoft gave us TryParse method, a good way to write cleaner code and improve performance avoiding costly Try-Catch blocks (judging by the messy code it was the last-minute addition, though). Sadly, for some reason the Enum type wasn't equipped with this useful feature. That means it is a good reason to try out some extensions...
The following code is a first attempt, which is more in line with the traditional TryParse syntax:
public static bool TryParse(this Enum theEnum, Type enumType, object value, out Enum result)
{
result = theEnum;
foreach (string item in Enum.GetNames(enumType))
{
if (item.Equals(value))
{
result = (Enum)Enum.Parse(enumType, value.ToString());
return true;
}
}
if (Enum.IsDefined(enumType, Convert.ChangeType(value, (Enum.GetUnderlyingType(enumType)))))
{
result = (Enum)Enum.Parse(enumType, value.ToString());
return true;
}
return false;
}
The usage is obvious:
bool result = type.TryParse(typeof(StatusEnum), "SerialMonogamist", out parsedEnum);
I avoided using a brute force approach with catching parsing errors - it defeats the whole purpose of having TryParse in the first place. The parse attempt is split into string and number parsing. The reason I didn't use the
Enum.IsDefined(enumType, value) for strings is it will fail for a numeric values with type different from the enum's underlying type. I assumed that parsing Int16 or Int64 to the Int32-based enum should work flawlessly (mind the Overflow exception).
A little bit different but more elegant code with generics:
public static bool TryParse<T>(this T theEnum, object value, out T result)
{
result = theEnum;
foreach (string item in Enum.GetNames(typeof(T)))
{
if (item.Equals(value))
{
result = (T)Enum.Parse(typeof(T), value.ToString());
return true;
}
}
if (Enum.IsDefined(typeof(T), Convert.ChangeType(value, (Enum.GetUnderlyingType(typeof(T))))))
{
result = (T)Enum.Parse(typeof(T), value.ToString());
return true;
}
return false;
}
The method call looks cleaner (CLR is smart enough to deduce a proper signature even if generic type is omitted) but a bit less readable:
bool result = theEnum.TryParse("HonestHusband", out parsedEnum);
I've put some small
test coverage project together and you can use it when trying to perfect my humble code. Good luck! Now it should be less reasons to
hate C# generics :)