鉴于c#不能切换类型(我收集到没有作为特殊情况添加,因为关系意味着可能应用多个不同的情况),有没有更好的方法来模拟类型切换?
void Foo(object o)
{
if (o is A)
{
((A)o).Hop();
}
else if (o is B)
{
((B)o).Skip();
}
else
{
throw new ArgumentException("Unexpected type: " + o.GetType());
}
}
我将创建一个接口,其名称和方法名称对您的交换机有意义,让我们分别调用它们:IDoable,告诉实现void Do()。
public interface IDoable
{
void Do();
}
public class A : IDoable
{
public void Hop()
{
// ...
}
public void Do()
{
Hop();
}
}
public class B : IDoable
{
public void Skip()
{
// ...
}
public void Do()
{
Skip();
}
}
修改方法如下:
void Foo<T>(T obj)
where T : IDoable
{
// ...
obj.Do();
// ...
}
至少这样你在编译时是安全的,而且我认为在性能方面它比在运行时检查类型要好。
正如Pablo所建议的,界面方法几乎总是处理这个问题的正确方法。要真正利用switch,另一种方法是在类中使用自定义枚举来表示类型。
enum ObjectType { A, B, Default }
interface IIdentifiable
{
ObjectType Type { get; };
}
class A : IIdentifiable
{
public ObjectType Type { get { return ObjectType.A; } }
}
class B : IIdentifiable
{
public ObjectType Type { get { return ObjectType.B; } }
}
void Foo(IIdentifiable o)
{
switch (o.Type)
{
case ObjectType.A:
case ObjectType.B:
//......
}
}
这也是在BCL中实现的。MemberInfo就是一个例子。MemberTypes,另一个是GetTypeCode用于基本类型,比如:
void Foo(object o)
{
switch (Type.GetTypeCode(o.GetType())) // for IConvertible, just o.GetTypeCode()
{
case TypeCode.Int16:
case TypeCode.Int32:
//etc ......
}
}
根据c# 7.0规范,你可以在开关的情况下声明一个局部变量的作用域:
object a = "Hello world";
switch (a)
{
case string myString:
// The variable 'a' is a string!
break;
case int myInt:
// The variable 'a' is an int!
break;
case Foo myFoo:
// The variable 'a' is of type Foo!
break;
}
这是做这件事的最佳方式,因为它只涉及强制转换和栈上推操作,这是解释器可以运行的最快的操作之一,只是在位操作和布尔条件之前。
与使用Dictionary<K, V>相比,这里占用的内存更少,计算量基本为零。
另一方面,这应该和使用if语句链一样快(如果不是更快的话):
object a = "Hello world";
if (a is string)
{
// The variable 'a' is a string!
} else if (a is int)
{
// The variable 'a' is an int!
} // etc.