如果您想
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()
?
这不会直接解决您的问题,因为您想打开自己的用户定义类型,但为了其他只想打开内置类型的人的利益,您可以使用 TypeCode 枚举:
switch (Type.GetTypeCode(node.GetType()))
{
case TypeCode.Decimal:
// Handle Decimal
break;
case TypeCode.Int32:
// Handle Int32
break;
...
}
如果我真的必须
switch
在对象类型上,我会使用.ToString()
。然而,我会不惜一切代价避免它:IDictionary<Type, int>
会做得更好,visitor可能有点矫枉过正,但除此之外它仍然是一个完美的解决方案。
在 MSDN 博客文章 许多问题:打开类型 中提供了一些关于为什么 .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; })
我面临着同样的问题并发现了这篇文章。 这就是 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 语句。在这种情况下:
Type nodeType = node.GetType();
if (nodeType == typeof(CasusNodeDTO))
{
}
else ...
另一种方法是:
if (node is CasusNodeDTO)
{
}
else ...
第一个示例仅适用于精确类型,后者也会检查继承。
你可以这样做:
function void PrintType(Type t) {
var t = true;
new Dictionary<Type, Action>{
{typeof(bool), () => Console.WriteLine("bool")},
{typeof(int), () => Console.WriteLine("int")}
}[t.GetType()]();
}
它清晰且简单。 它比在某处缓存字典慢一点..但是对于很多代码来说这并不重要..
你可以这样做:
if (node is CasusNodeDTO)
{
...
}
else if (node is BucketNodeDTO)
{
...
}
...
虽然这会更优雅,但它可能不如这里的其他一些答案那么有效。
一种方法是向 NodeDTO 添加纯虚拟 GetNodeType() 方法,并在后代中重写它,以便每个后代返回实际类型。
根据您在 switch 语句中所做的操作,正确的答案是多态性。只需在接口/基类中放置一个虚函数并为每个节点类型重写即可。
我实际上更喜欢这里给出的答案的方法: 还有比这更好的替代方案来“打开类型”吗?
然而,关于在 C# 等面向对象语言中不实现任何类型比较方法,有一个很好的论点。作为替代方案,您可以使用继承来扩展和添加额外的所需功能。
这一点在作者博客的评论中进行了讨论: http://blogs.msdn.com/b/jaredpar/archive/2008/05/16/switching-on-types.aspx#8553535
我发现这是一个非常有趣的点,它改变了我在类似情况下的方法,只希望这对其他人有帮助。
亲切的问候,韦恩