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

如下例所示:

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

问题是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的post; 这是一个很好的解释。

但是,您可以使用TypeCode处理简单类型。

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

我会在彼得的优秀分析中加入以下思想:

基本上,“转换”的目的是选择一些不同的可能性之一 。 给定的枚举值,整数,布尔值或字符串类型只能是一个值,因此“切换”这样的值是有意义的。 但类型根本不同。 给定值通常有许多类型。 类型经常重叠 。 所提出的“类型开关”与开关结构的所述目的不匹配。

Peter Hallam在MSDN上发表了一篇很好的博客文章 ,解释了切换非常量值的问题。

“案例标签的顺序在确定执行哪个代码块时变得非常重要。因为案例标签表达式不是常量,编译器无法validation案例标签的值是否不同,所以这是一种必须满足的可能性。这与大多数程序员对switch语句的直觉在很多方面背道而驰。大多数程序员都会惊讶地发现改变他们的case块的顺序改变了他们程序的含义。为了扭转它,这将是令人惊讶的如果打开的表达式等于案例标签中的表达式,但控件没有转到该标签。“

你可以做到

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

这是有效的,因为切换仅适用于原始类型(正如其他人所说)。

这是typeof不是常量,case必须是常量。

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(..))”完成的,只有很少的情况和一个包含许多情况的字典。 这两种方法都是针对所有.NET类型定义的,因为System.Object具有虚拟的Equals和GetHashCode。

可以说,“切换可以使用任何类型的表达式,其中Equals和GetHashCode被覆盖”,这会自动限定字符串,类型等。是的,错误的Equals / GetHashCode实现会破坏switch语句,但是,嘿,你也可以打破“==”运算符,“foreach”循环,以及其他一些东西,所以我真的没有看到程序员的错误打破了开关的“大问题”。 但即使他们不想为所有类型允许它,无论出于何种原因,当然Type是安全的,因为Type.Equals()定义良好,并且也实现了GetHashCode。

另外,我不认为你考虑inheritance的论点; switch转到其常量(和type(int)是常量,不要错误)的情况等于表达式 – inheritance是Type类型的另一个“行为”。 人们甚至不需要考虑inheritance,我的意思是,我们拒绝比较2个对象只是因为它们具有其他特性吗? 不,我们不这样做,因为总是定义平等。 基本上,重点是,不同类型之间没有重叠。

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