繁体   English   中英

为什么C#switch语句不允许使用typeof / GetType()?

[英]Why doesn't C# switch statement allow using typeof/GetType()?

如本例所示:

switch ( myObj.GetType ( ) )
{
    case typeof(MyObject):
        Console.WriteLine ( "MyObject is here" );
        break;
}

在Peter Hallam的职位上排名第二; 这是一个很好的解释。

不过,您可以使用TypeCode处理简单类型。

switch (Type.GetTypeCode(myObj.GetType())) {
    case TypeCode.Boolean: ...
    case TypeCode.Char: ...
    case TypeCode.String: ...
    case TypeCode.Object: ...
    default: ...
} 

我将在彼得的出色分析中加入以下思想:

刚出生时,“转换”的目的是从一些不同的可能性中选择一种 枚举,整数,布尔值或字符串类型的给定值只能是一个值,因此“切换”该值是有意义的。 但是类型根本不同。 给定值通常具有许多类型。 类型经常重叠 提出的“类型开关”与开关构造的既定目的不匹配。

问题是(根据规范) switch (仅适用于原语(int等)和字符串)。 但是,是的, 具有F#样式匹配会很好。

从§8.7.2开始:

 switch-label: case constant-expression : default : 

... switch语句的控制类型由switch表达式建立。 如果switch表达式的类型是sbyte,byte,short,ushort,int,uint,long,ulong,char,string或enum-type,则这就是switch语句的控制类型。 否则,从switch表达式的类型到以下可能的控制类型之一,必须存在一个用户定义的隐式转换(第6.4节):sbyte,byte,short,ushort,int,uint,long,ulong,char,string 。 如果不存在这样的隐式转换,或者存在多个这样的隐式转换,则会发生编译时错误。

但是很明显,使用这样的受限集可以实现简单(有效)的IL。 请注意, string是通过字典映射处理为整数的。

Peter Hallam在MSDN上有一篇不错的博客文章,其中解释了启用非恒定值的问题。

“案例标签的顺序对于确定执行哪个代码块非常重要。由于案例标签的表达式不是恒定的,因此编译器无法验证案例标签的值是不同的,因此这是必须解决的可能性这与大多数程序员通过几种方式对switch语句的直觉背道而驰,大多数程序员会惊讶地发现,改变其case块的顺序会改变其程序的含义。如果打开的表达式等于case标签中的表达式,但控件没有转到该标签。”

你可以做

switch ( myObj.GetType().Name )
{
    case "MyObject":
        Console.WriteLine ( "MyObject is here" );
        break;
}

之所以可行,是因为切换仅适用于原始类型(如其他人所述)。

就是typeof不是常数,而且情况必须是常数。

C#中的开关仅适用于整数或字符串。 myObj.GetType()返回一个Type,它既不是整数也不是字符串。

你为什么不只是tostring()呢?

在C#7.0中,您可以执行此操作。 请参见C#7.0案例块中的模式匹配

// ----- Assume that spaceItem is of type SpaceType,
//       and that Planet and Star derive from SpaceType.
switch (spaceItem)
{
  case Planet p:
    if (p.Type != PlanetType.GasGiant)
      LandSpacecraft(p);
    break;
  case Star s:
    AvoidHeatSource(s);
    break;
  case null:
    // ----- If spaceItem is null, processing falls here,
    //       even if it is a Planet or Star null instance.
    break;
  default:
    // ----- Anything else that is not Planet, Star, or null.
    break;
}

除了懒惰之外,没有充分的理由让MS不执行类型切换。

字符串切换是通过使用“ if(.. Equals(..))”(少用)和Dictionary(多用)来完成的。 这两种方法都是为所有.NET类型定义的,因为System.Object具有虚拟的Equals和GetHashCode。

有人会说,“ switch可以使用覆盖Equals和GetHashCode的任何类型的表达式”,它会自动限定字符串,Type等。是的,糟糕的Equals / GetHashCode实现会破坏switch语句,但是,您也可以破坏“ ==”运算符,“ foreach”循环以及许多其他内容,所以我真的看不到“大问题”,因为程序员的错误破坏了开关。 但是,即使出于某种原因,即使他们不想允许所有类型都使用它,也可以肯定Type是安全的,因为Type.Equals()是定义明确的,并且还实现了GetHashCode。

另外,我不赞成您考虑继承的说法。 切换到常量(并且type(int)是一个常量,请不要误解)等于表达式的情况-继承是Type类型的另一个“行为”。 一个人甚至不需要考虑继承,我的意思是,我们是否仅因为两个对象具有其他特性而拒绝比较它们? 不,我们不这样做,因为总是定义平等。 基本上,重点是,不同类型之间没有重叠。

因此,正如我所说,只有一个原因和一个原因:懒惰。 :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM