C# Switching on Types
March 8, 2010 Leave a comment
Have you ever wanted to do this?
Type t = typeof(int);
switch (t) {
case typeof(int):
Console.WriteLine("int!");
break;
case typeof(string):
Console.WriteLine("string!");
break;
default:
Console.WriteLine("unknown!");
break;
}
Doesn’t work, right? Throws ‘A value of an integral type expected’. This is because C# switch statement is picky when it evaluates the cases. It wants static values and can’t get fancy with object comparisons. Switch statements aren’t just a bunch of if/else statements when boiled down to IL. There is more detail in this StackOverflow question.
So we’re out of luck, right? Not so fast. Let’s think about what we want: behavior associated with a .NET type. How can we accomplish that? I got an idea from Judah’s answer to the aforementioned SO question. Judah uses a generic dictionary to associate the actual type, as the key, with a string. Interesting. Why not associate behavior with those types instead? With delegates like Action<T> and Func<T>, we can do that.
Here is Judah’s answer refactored to use a generic dictionary:
Type someType = typeof(int);
Dictionary<Type, Func<string>> typeTable = new Dictionary<Type, Func<string>>();
typeTable.Add(typeof(string), () => { return "It's a string!"; });
typeTable.Add(typeof(int), () => { return "It's an int!"; });
Console.Write(typeTable[someType].Invoke());
Now we can call any of a number of associated delegates based on a Type object. We can get even fancier if we want, using Action<T> if we don’t need a return value or Func<T, TResult> if we want to pass parameters into the behavior. We get the usual performance hit of using delegates, but unless you’re guiding a missile in real time I don’t think it’s a dealbreaker.
I’ve used this technique and it works great for me, hope you find it useful as well.