Using Case/Switch and GetType to determine the object
C#.NetReflectionSwitch StatementCaseC# Problem Overview
> Possible Duplicate:
> C# - Is there a better alternative than this to ‘switch on type’?
If you want to switch
on a type of object, what is the best way to do this?
Code snippet
private int GetNodeType(NodeDTO node)
{
switch (node.GetType())
{
case typeof(CasusNodeDTO):
return 1;
case typeof(BucketNodeDTO):
return 3;
case typeof(BranchNodeDTO):
return 0;
case typeof(LeafNodeDTO):
return 2;
default:
return -1;
}
}
I know this doesn't work that way, but I was wondering how you could solve this.
Is an if/else
statement appropriate in this case?
Or do you use the switch and add .ToString()
to the type?
C# Solutions
Solution 1 - C#
This won't directly solve your problem as you want to switch on your own user-defined types, but for the benefit of others who only want to switch on built-in types, you can use the TypeCode enumeration:
switch (Type.GetTypeCode(node.GetType()))
{
case TypeCode.Decimal:
// Handle Decimal
break;
case TypeCode.Int32:
// Handle Int32
break;
...
}
Solution 2 - C#
If I really had to switch
on type of object, I'd use .ToString()
. However, I would avoid it at all costs: IDictionary<Type, int>
will do much better, visitor might be an overkill but otherwise it is still a perfectly fine solution.
Solution 3 - C#
In the MSDN blog post Many Questions: switch on type is some information on why .NET does not provide switching on types.
As usual - workarounds always exists.
This one isn't mine, but unfortunately I have lost the source. It makes switching on types possible, but I personally think it's quite awkward (the dictionary idea is better):
public class Switch
{
public Switch(Object o)
{
Object = o;
}
public Object Object { get; private set; }
}
/// <summary>
/// Extensions, because otherwise casing fails on Switch==null
/// </summary>
public static class SwitchExtensions
{
public static Switch Case<T>(this Switch s, Action<T> a)
where T : class
{
return Case(s, o => true, a, false);
}
public static Switch Case<T>(this Switch s, Action<T> a,
bool fallThrough) where T : class
{
return Case(s, o => true, a, fallThrough);
}
public static Switch Case<T>(this Switch s,
Func<T, bool> c, Action<T> a) where T : class
{
return Case(s, c, a, false);
}
public static Switch Case<T>(this Switch s,
Func<T, bool> c, Action<T> a, bool fallThrough) where T : class
{
if (s == null)
{
return null;
}
T t = s.Object as T;
if (t != null)
{
if (c(t))
{
a(t);
return fallThrough ? s : null;
}
}
return s;
}
}
Usage:
new Switch(foo)
.Case<Fizz>
(action => { doingSomething = FirstMethodCall(); })
.Case<Buzz>
(action => { return false; })
Solution 4 - C#
I'm faced with the same problem and came across this post. Is this what's meant by the IDictionary approach:
Dictionary<Type, int> typeDict = new Dictionary<Type, int>
{
{typeof(int),0},
{typeof(string),1},
{typeof(MyClass),2}
};
void Foo(object o)
{
switch (typeDict[o.GetType()])
{
case 0:
Print("I'm a number.");
break;
case 1:
Print("I'm a text.");
break;
case 2:
Print("I'm classy.");
break;
default:
break;
}
}
If so, I can't say I'm a fan of reconciling the numbers in the dictionary with the case statements.
This would be ideal but the dictionary reference kills it:
void FantasyFoo(object o)
{
switch (typeDict[o.GetType()])
{
case typeDict[typeof(int)]:
Print("I'm a number.");
break;
case typeDict[typeof(string)]:
Print("I'm a text.");
break;
case typeDict[typeof(MyClass)]:
Print("I'm classy.");
break;
default:
break;
}
}
Is there another implementation I've overlooked?
Solution 5 - C#
I'd just use an if statement. In this case:
Type nodeType = node.GetType();
if (nodeType == typeof(CasusNodeDTO))
{
}
else ...
The other way to do this is:
if (node is CasusNodeDTO)
{
}
else ...
The first example is true for exact types only, where the latter checks for inheritance too.
Solution 6 - C#
You can do this:
function void PrintType(Type t) {
var t = true;
new Dictionary<Type, Action>{
{typeof(bool), () => Console.WriteLine("bool")},
{typeof(int), () => Console.WriteLine("int")}
}[t.GetType()]();
}
It's clear and its easy. It a bit slower than caching the dictionary somewhere.. but for lots of code this won't matter anyway..
Solution 7 - C#
You can do this:
if (node is CasusNodeDTO)
{
...
}
else if (node is BucketNodeDTO)
{
...
}
...
While that would be more elegant, it's possibly not as efficient as some of the other answers here.
Solution 8 - C#
One approach is to add a pure virtual GetNodeType() method to NodeDTO and override it in the descendants so that each descendant returns actual type.
Solution 9 - C#
Depending on what you are doing in the switch statement, the correct answer is polymorphism. Just put a virtual function in the interface/base class and override for each node type.
Solution 10 - C#
I actually prefer the approach given as the answer here: https://stackoverflow.com/questions/298976/c-sharp-is-there-a-better-alternative-than-this-to-switch-on-type
There is however a good argument about not implementing any type comparison methids in an object oriented language like C#. You could as an alternative extend and add extra required functionality using inheritance.
This point was discussed in the comments of the authors blog here: http://blogs.msdn.com/b/jaredpar/archive/2008/05/16/switching-on-types.aspx#8553535
I found this an extremely interesting point which changed my approach in a similar situation and only hope this helps others.
Kind Regards, Wayne