为什么';tc#switch语句是否允许使用typeof/GetType()?
如本例所示:为什么';tc#switch语句是否允许使用typeof/GetType()?,c#,.net,reflection,switch-statement,C#,.net,Reflection,Switch Statement,如本例所示: switch ( myObj.GetType ( ) ) { case typeof(MyObject): Console.WriteLine ( "MyObject is here" ); break; } 这是因为typeof不是常数,case必须是常数。C#中的开关仅适用于整数或字符串。myObj.GetType()返回一个类型,该类型既不是整数也不是字符串。有一个例子解释了打开非常量值的问题 “案例标签的顺序变为 在确定哪个块时有重
switch ( myObj.GetType ( ) )
{
case typeof(MyObject):
Console.WriteLine ( "MyObject is here" );
break;
}
这是因为typeof不是常数,case必须是常数。C#中的开关仅适用于整数或字符串。myObj.GetType()返回一个类型,该类型既不是整数也不是字符串。有一个例子解释了打开非常量值的问题 “案例标签的顺序变为 在确定哪个块时有重要意义 因为 不支持大小写标签表达式 编译器无法验证的常量 案例标签的值是 不同,所以这是一种可能性 这是必须满足的,这是 与大多数程序员的直觉相反 关于一对夫妇中的switch语句 当然。大多数程序员都是这样 惊讶地发现改变 他们案件的顺序改变了案件的审理顺序 他们计划的意义。把它转过来 如果 打开的表达式是相等的 到大小写标签中的表达式,但 控件未转到该标签。“
问题是
开关(根据规范)仅适用于原语(int等)和字符串。但是,是的,那太好了
根据§8.7.2:
。。。
switch语句的控制类型由switch表达式建立。
如果开关表达式的类型为sbyte、byte、short、ushort、int、uint、long,
ulong、char、string或枚举类型,则这是开关的管理类型
陈述否则,只能存在一个用户定义的隐式转换(§6.4)
将开关表达式的类型转换为以下可能的控制类型之一:
sbyte、byte、short、ushort、int、uint、long、ulong、char、string。如果没有这样的暗示
存在转换,或者如果存在多个此类隐式转换,则为编译时
发生错误
然而,很明显,使用这样一个受限制的集合可以实现简单(高效)的IL。请注意,string
是通过字典映射到整数来处理的。为什么不直接使用string()来处理它呢?Peter Hallam文章的第二部分;这是一个很好的解释
不过,您可以使用类型代码处理简单类型
switch (Type.GetTypeCode(myObj.GetType())) {
case TypeCode.Boolean: ...
case TypeCode.Char: ...
case TypeCode.String: ...
case TypeCode.Object: ...
default: ...
}
你可以
switch ( myObj.GetType().Name )
{
case "MyObject":
Console.WriteLine ( "MyObject is here" );
break;
}
这是因为切换只在基本类型上起作用(正如其他人所说)。我想在Peter出色的分析中补充以下思想:
基本上,“切换”的目的是从一些不同的可能性中选择一种。enum、integer、Boolean或string类型的给定值只能是一个值,因此“切换”这样的值是有意义的。但类型是根本不同的。给定的值通常有多种类型。类型经常重叠。建议的“类型开关”与开关构造的规定目的不匹配。除了惰性之外,MS没有充分的理由不实施开关类型
字符串切换是使用“if(..Equals(..)”和一个字典来完成的。这两种方法都是为所有.NET类型定义的,因为System.Object具有虚拟的Equals和GetHashCode
可以说,“switch可以使用覆盖了Equals和GetHashCode的任何类型的表达式”,这会自动限定字符串、类型等。是的,坏的Equals/GetHashCode实现会破坏switch语句,但是嘿,你也可以破坏“==”操作符、“foreach”循环和其他一些东西,所以,我并不认为交换机被程序员的错误破坏有什么“大问题”。但即使他们不想允许所有类型都使用它,不管出于什么原因,类型肯定是安全的,因为Type.Equals()是定义良好的,并且还实现了GetHashCode
我也不赞成你考虑继承的论点;开关转到常量(类型(int)是常量,请不要搞错)等于表达式的情况-继承是类型的另一个“行为”。一个人甚至不需要考虑继承,我是说,我们拒绝比较2个对象仅仅是因为它们有其他的特性吗?不,我们没有,因为平等总是有定义的。基本上,重点是,不同类型之间没有重叠
正如我所说,只有一个原因,而且只有一个原因:懒惰 在C#7.0中,你可以做到。看见
@RHSeeger:在Petter Hallam的博客文章中没有一句话可以解释为“人们太愚蠢而无法理解这个概念”,也没有说语言设计师出于安全考虑,因为世界上有愚蠢的人。这与人们“太愚蠢”无关。彼得的观点是,人们会发现这种行为令人惊讶,而不是无法理解。C#经过精心设计,在任何可能的情况下都不会让人感到意外。如果您试图编写一个切换对象类型的switch
语句,那么您确实需要重构并将案例委托给对象实现。在一个设计良好的OO系统中,永远不需要这样做。请注意,打开对象类型是一种强烈的代码气味。打开类型以确定要执行的代码/要调用的方法就像说“我希望我在这里遇到的所有对象都有一个我现在可以调用的方法”。所以一个更好的问题可能是“为什么我必须打开对象类型?”当你回答这个问题时,解决问题而不是症状:)谢谢Marc。如果他们使用字典处理字符串,为什么MS不使用字典处理其他类型的字符串?vb.net允许开关中的任何内容however@joan因为它只适用于编译时常量(例如字符串literals)。密钥在IL代码中使用,因此需要在编译时知道time@Pondidum-我希望VB.Net开关只是在IL中实现一系列If。如果您单步执行,您是否看到代码在每个“案例”上都停止,而不是跳转到正确的案例
switch ( myObj.GetType().Name )
{
case "MyObject":
Console.WriteLine ( "MyObject is here" );
break;
}
// ----- 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;
}