使用Case / Switch和GetType来确定对象
可能重复:
C# – 有没有比这更好的替代“打开types”?
如果你想switch
一个types的对象,最好的办法是什么?
代码片段
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; } }
我知道这不是那种方式,但我想知道如何解决这个问题。 在这种情况下, if/else
语句是否恰当?
或者你使用开关,并添加.ToString()
的types?
如果我真的不得不switch
types的对象,我会使用.ToString()
。 但是,我会不惜一切代价避免它: IDictionary<Type, int>
会做得更好, 访问者可能是一个矫枉过正,但否则它仍然是一个完美的解决scheme。
这不会直接解决您的问题,因为您希望切换自己的用户定义types,但是为了其他只想切换内置types的用户,您可以使用TypeCode枚举:
switch (Type.GetTypeCode(node.GetType())) { case TypeCode.Decimal: // Handle Decimal break; case TypeCode.Int32: // Handle Int32 break; ... }
在MSDN博客文章中有许多问题:开启types是为什么.NET不提供types切换的一些信息。
像往常一样,变通办法始终存在。
这一个不是我的,但不幸的是我已经失去了源。 它使得可能的切换types,但我个人认为这是相当尴尬(字典的想法是更好的):
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; } }
用法:
new Switch(foo) .Case<Fizz> (action => { doingSomething = FirstMethodCall(); }) .Case<Buzz> (action => { return false; })
我只是使用一个if语句。 在这种情况下:
Type nodeType = node.GetType(); if (nodeType == typeof(CasusNodeDTO)) { } else ...
另一种方法是:
if (node is CasusNodeDTO) { } else ...
第一个例子只适用于确切的types,后者也检查inheritance。
我面临着同样的问题,并遇到这个职位。 这是什么意思的IDictionary方法:
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; } }
如果是这样的话,我不能说我是把字典中的数字与案例陈述调和起来的粉丝。
这将是理想的,但字典参考杀死它:
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; } }
我忽略了另一个实现吗?
你可以这样做:
if (node is CasusNodeDTO) { ... } else if (node is BucketNodeDTO) { ... } ...
虽然这可能会更优雅,但可能并不像其他答案那样高效。
一种方法是向NodeDTO添加一个纯虚拟GetNodeType()方法,并在后代中重写它,以便每个后代返回实际types。
你可以这样做:
function void PrintType(Type t) { var t = true; new Dictionary<Type, Action>{ {typeof(bool), () => Console.WriteLine("bool")}, {typeof(int), () => Console.WriteLine("int")} }[t.GetType()](); }
这很清楚,很容易。 这比caching字典的地方慢一点..但是对于大量的代码,这无关紧要..
根据你在switch语句中做什么,正确的答案是多态。 只需在接口/基类中放置一个虚拟函数,并覆盖每个节点types。
我会使用交换机顶部的string(Name):
private int GetNodeType(NodeDTO node) { switch (node.GetType().Name) { case "CasusNodeDTO": return 1; break; case "BucketNodeDTO": return 3; break; // ... default: return -1; break; } }
我其实更喜欢这里给出的方法: 有没有比这更好的替代方法来“打开types”?
然而有一个很好的论点,就是没有在像C#这样的面向对象的语言中实现任何types的比较方法。 您可以select使用inheritance扩展并添加额外的必需function。
这一点在作者博客的评论里讨论过: http : //blogs.msdn.com/b/jaredpar/archive/2008/05/16/switching-on-types.aspx#8553535
我发现这是一个非常有趣的观点,改变了我在类似情况下的做法,只希望这有助于其他人。
亲切的问候,韦恩