简体   繁体   English

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

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

As in this example: 如本例所示:

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

Second on Peter Hallam's post; 在Peter Hallam的职位上排名第二; it's a great explanation. 这是一个很好的解释。

You can use TypeCode to work with simple types, though. 不过,您可以使用TypeCode处理简单类型。

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

I would add to Peter's excellent analysis the following thought: 我将在彼得的出色分析中加入以下思想:

Fundamenatally, the purpose of a "switch" is to choose one of some number of distinct possibilities . 刚出生时,“转换”的目的是从一些不同的可能性中选择一种 A given value of enum, integer, Boolean or string type can only be one value, so it makes sense to "switch" on such a value. 枚举,整数,布尔值或字符串类型的给定值只能是一个值,因此“切换”该值是有意义的。 But types are fundamentally different. 但是类型根本不同。 A given value usually has many types. 给定值通常具有许多类型。 Types frequently overlap . 类型经常重叠 The proposed "type switch" does not match the stated purpose of the switch construct. 提出的“类型开关”与开关构造的既定目的不匹配。

The problem is that switch (per the spec) only works with primitives (int etc) and strings. 问题是(根据规范) switch (仅适用于原语(int等)和字符串)。 But yes, it would be nice to have F#-style matching . 但是,是的, 具有F#样式匹配会很好。

From §8.7.2: 从§8.7.2开始:

 switch-label: case constant-expression : default : 

... The governing type of a switch statement is established by the switch expression. ... switch语句的控制类型由switch表达式建立。 If the type of the switch expression is sbyte, byte, short, ushort, int, uint, long, ulong, char, string, or an enum-type, then that is the governing type of the switch statement. 如果switch表达式的类型是sbyte,byte,short,ushort,int,uint,long,ulong,char,string或enum-type,则这就是switch语句的控制类型。 Otherwise, exactly one user-defined implicit conversion (§6.4) must exist from the type of the switch expression to one of the following possible governing types: sbyte, byte, short, ushort, int, uint, long, ulong, char, string. 否则,从switch表达式的类型到以下可能的控制类型之一,必须存在一个用户定义的隐式转换(第6.4节):sbyte,byte,short,ushort,int,uint,long,ulong,char,string 。 If no such implicit conversion exists, or if more than one such implicit conversion exists, a compile-time error occurs. 如果不存在这样的隐式转换,或者存在多个这样的隐式转换,则会发生编译时错误。

It is obvious, however, that working with such a restricted set allows for simple (and efficient) IL. 但是很明显,使用这样的受限集可以实现简单(有效)的IL。 Note that string is handled via a dictionary map to an integer. 请注意, string是通过字典映射处理为整数的。

There's a good blog post on MSDN by Peter Hallam which explains the problems of switching on non-constant values. Peter Hallam在MSDN上有一篇不错的博客文章,其中解释了启用非恒定值的问题。

"The order of the case labels becomes significant in determining which block of code gets executed. Because the case label expressions are not constant the compiler cannot verify that the values of the case labels are distinct, so this is a possibility which must be catered to. This runs counter to most programmers' intuition about the switch statement in a couple of ways. Most programmers would be surprised to learn that changing the order of their case blocks changed the meaning of their program. To turn it around, it would be surprising if the expression being switched on was equal to an expression in a case label, but control didn't go to that label." “案例标签的顺序对于确定执行哪个代码块非常重要。由于案例标签的表达式不是恒定的,因此编译器无法验证案例标签的值是不同的,因此这是必须解决的可能性这与大多数程序员通过几种方式对switch语句的直觉背道而驰,大多数程序员会惊讶地发现,改变其case块的顺序会改变其程序的含义。如果打开的表达式等于case标签中的表达式,但控件没有转到该标签。”

You could do 你可以做

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

This works because switching only works on primitive types (as others have said). 之所以可行,是因为切换仅适用于原始类型(如其他人所述)。

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

a switch in C# only works for integrals or strings. C#中的开关仅适用于整数或字符串。 myObj.GetType() returns a Type, which is neither an integral or a string. myObj.GetType()返回一个Type,它既不是整数也不是字符串。

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

In C# 7.0 you can do it. 在C#7.0中,您可以执行此操作。 See Pattern Matching in C# 7.0 Case Blocks 请参见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;
}

There's no good reason for MS not to implement switching on types, other than laziness. 除了懒惰之外,没有充分的理由让MS不执行类型切换。

String switching is accomplished using "if(..Equals(..))"s with few cases and a Dictionary with many cases. 字符串切换是通过使用“ if(.. Equals(..))”(少用)和Dictionary(多用)来完成的。 Both of those approaches are defined for all .NET types, because System.Object has Equals and GetHashCode that are virtual. 这两种方法都是为所有.NET类型定义的,因为System.Object具有虚拟的Equals和GetHashCode。

One could say that, "switch can use expression of any type where Equals and GetHashCode are overridden", which automatically qualifies string, Type, etc. Yes, bad Equals/GetHashCode implementation will break the switch statement, but hey, you can also break the "==" operator, the "foreach" loop, and a bunch of other stuff, so I don't really see the "big problem" with switch being broken by programmer's mistake. 有人会说,“ switch可以使用覆盖Equals和GetHashCode的任何类型的表达式”,它会自动限定字符串,Type等。是的,糟糕的Equals / GetHashCode实现会破坏switch语句,但是,您也可以破坏“ ==”运算符,“ foreach”循环以及许多其他内容,所以我真的看不到“大问题”,因为程序员的错误破坏了开关。 But even if they don't want to allow it for all types, for whatever reason, certainly Type is safe, because Type.Equals() is well-defined and GetHashCode is also implemented. 但是,即使出于某种原因,即使他们不想允许所有类型都使用它,也可以肯定Type是安全的,因为Type.Equals()是定义明确的,并且还实现了GetHashCode。

Also, I don't buy the argument that you have consider inheritance; 另外,我不赞成您考虑继承的说法。 switch goes to the case whose constant (and type(int) is a constant, make no mistake about that) is equal to the expression - inheritance is another "behavior" of the type Type. 切换到常量(并且type(int)是一个常量,请不要误解)等于表达式的情况-继承是Type类型的另一个“行为”。 One doesn't even need to consider inheritance, I mean, do we refuse to compare 2 objects just because they have other qualities? 一个人甚至不需要考虑继承,我的意思是,我们是否仅因为两个对象具有其他特性而拒绝比较它们? No, we don't, because equality is always defined. 不,我们不这样做,因为总是定义平等。 Basically, point is, there's no overlapping between different types. 基本上,重点是,不同类型之间没有重叠。

So as I said, there's one reason and one reason only: laziness. 因此,正如我所说,只有一个原因和一个原因:懒惰。 :) :)

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

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