使用 Case/Switch 和 GetType 来确定对象

可能的复制品:
C #-有没有比这更好的选择来“打开类型”?

如果你想对一类对象使用 switch,最好的方法是什么?

代码片段

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()添加到类型中?

305877 次浏览

如果 真的必须在对象类型上使用 switch,我会使用 .ToString()。然而,我会不惜一切代价避免它: IDictionary<Type, int>将做得更好,访客可能是一个过度杀伤,但否则它仍然是一个完美的解决方案。

我会使用 if 语句,在这个例子中:

Type nodeType = node.GetType();
if (nodeType == typeof(CasusNodeDTO))
{
}
else ...

另一种方法是:

if (node is CasusNodeDTO)
{
}
else ...

第一个示例只适用于精确类型,后者也检查继承。

你可以这样做:

if (node is CasusNodeDTO)
{
...
}
else if (node is BucketNodeDTO)
{
...
}
...

虽然这样会更优雅,但它可能没有这里的其他一些答案那么高效。

一种方法是向 NodeDTO 添加一个纯虚拟 GetNodeType ()方法,并在子代中重写它,以便每个子代返回实际类型。

根据在 switch 语句中的操作,正确的答案是多态性。只需在接口/基类中放入一个虚函数,并为每个节点类型重写。

在 MSDN blog post 很多问题: 打开类型中有一些关于为什么 .NET不提供类型开关的信息。

像往常一样,变通方法总是存在的。

这个不是我的,但不幸的是我找不到源头了。它使类型的转换成为可能,但我个人认为这是相当尴尬的(字典的想法更好) :

  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; })

我遇到了同样的问题,并且看到了这篇文章。 这就是字典里的解释吗:

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;
}
}

还有其他我忽略的实现吗?

你可以这样做:

function void PrintType(Type t) {
var t = true;
new Dictionary<Type, Action>{
{typeof(bool), () => Console.WriteLine("bool")},
{typeof(int),  () => Console.WriteLine("int")}
}[t.GetType()]();
}

很清楚,很简单。 它比缓存字典要慢一些,但是对于大量的代码来说,这并不重要。

这不会直接解决您的问题,因为您想要切换到您自己的用户定义类型,但是为了那些只想切换到内置类型的人的利益,您可以使用 类型代码枚举:

switch (Type.GetTypeCode(node.GetType()))
{
case TypeCode.Decimal:
// Handle Decimal
break;


case TypeCode.Int32:
// Handle Int32
break;
...
}

实际上,我更喜欢这里给出的答案: 有没有比这更好的替代开关类型 & # 39; ?

然而,在 C # 这样的面向对象语言中不实现任何类型比较方法是一个很好的论点。您可以作为替代扩展,并使用继承添加额外的必需功能。

这一点在作者博客的评论中得到了讨论: Http://blogs.msdn.com/b/jaredpar/archive/2008/05/16/switching-on-types.aspx#8553535

我发现这是一个非常有趣的观点,它改变了我在类似情况下的做法,只希望这能帮助其他人。

问候你,韦恩