Wednesday, March 25, 2009

An Elegant Way to Parse C# Enums

If you're like me, you find the standard .NET way to parse Enums pretty awkward:

string aStr = "Truncate";
FileInfo aFN = (FileInfo) Enum.Parse(
typeof(FileInfo), aStr);

First, we have to provide the type of the enumeration twice. Second, I personally hate nested parentheses. I just cannot read the code with too many parentheses.

What I suggest is a thin wrapper:

public static class EnumParser<tEnum>
where tEnum : struct
{
public static tEnum Parse(string theVal)
{
return (tEnum)Enum.Parse(
typeof(tEnum), theVal);
}

public static tEnum Parse(string theVal, tEnum theDef)
{
try { return Parse(theVal); }
catch (ArgumentException) { return theDef; }
}
}

After several years of programming in C# I found I constantly use the exact same approach in most or all of my projects so I added it to my small C# toolkit.

The initial example would look more elegant with this new class in scope:

string aStr = "Truncate";
FileInfo aFN = EnumParser<FileInfo>.Parse(aStr);

The second overload allows us to use a default value:

string aStr = "Unknown";
FileInfo aFN = EnumParser<FileInfo>.Parse(
aStr, FileInfo.Truncate);

The provided solution is good but not perfect. Let's create another version of the EnumParser class:

public static class EnumParser
{
public static tEnum Parse<tEnum>(
string theVal) where tEnum : struct
{
return (tEnum)Enum.Parse(
typeof(tEnum), theVal);
}

public static tEnum Parse<tEnum>(
string theVal, tEnum theDef) where tEnum : struct
{
try { return Parse<tEnum>(theVal); }
catch (ArgumentException) { return theDef; }
}
}

As you see, we moved from a generic type to a non-generic type with two generic methods. Now let's look at the usage:

string aStr = "Truncate";
FileInfo aFN = EnumParser.Parse<FileInfo>(aStr);

The usage example when we don't specify a default value is almost identical to that of the generic type. However, things change significantly when a default value comes into play:

string aStr = "Unknown";
FileInfo aFN = EnumParser.Parse(aStr, FileInfo.Truncate);

As you see, we don't even specify the generic method arguments and the code will still compile successfully. The reason is: the compiler can resolve the arguments of the generic method from the argument that we specified. Our default value argument has now two roles: first, it is the value that will be returned in case the string is not recognized; second, it is an implicit type specifier for a generic method.

This is, of course, my favorite way to parse enums.

Cheers,
Kirill

Tuesday, March 24, 2009

Using AJAX CascadingDropDown Extender with Page.EnableEventValidation Set to True

Using the CascadingDropDown control extender that ships with the AJAX Control Toolkit requires that EnableEventValidation property of the Page containing the target DropDownList control be set to false.
However, this can potentially expose our page to a malicious attack, since nothing can then prevent "generated" post-backs.
A more elegant approach is creating a class that derives from DropDownList as follows:

public class NoValidationDropDownList : DropDownList
{ }

After the class has been created, all we need to do is replace the instances of the DropDownList class with respective instances of the NoValidationDropDownList class.

The reason why this works is simple: ASP.NET only validates controls that are marked with the SupportsEventValidation attribute. Since our class is not marked with this attribute, ASP.NET does not validate items on post-back and, consequently, no exception is thrown.

Cheers,
Kirill