首页 / 知识
关于C#switch语句限制:C#switch语句限制 – 为什么?
2023-04-14 06:33:00

C# switch statement limitations - why?在编写switch语句时,在case语句中可以打开的内容似乎有两个限制。 例如(是的,我知道,如果你在做这种事情,这可能意味着你的面向对象(OO)架构不确定——这只是一个人为的例子!),
此处switch()语句失败,应为"整型值",case语句失败,应为"常量值"。 为什么有这些限制,以及根本的理由是什么?我看不出为什么switch语句必须只服从静态分析,以及为什么被打开的值必须是整数(也就是说,原语)。理由是什么? 重要的是不要将C switch语句与CIL switch指令混淆。 cil开关是一个跳转表,它需要一组跳转地址的索引。 只有当C开关的外壳相邻时,这才有用:
但如果没有,就没什么用了:
(您需要一张3000个条目的表格,只有3个插槽) 对于非相邻表达式,编译器可能会开始执行线性if else检查。 对于较大的非相邻表达式集,编译器可以从二叉树搜索开始,最后如果不是,则从最后几个项开始。 如果表达式集包含相邻项的丛,编译器可以二叉树搜索,最后是CIL开关。 这满是"mays"和"mights",它依赖于编译器(可能与mono或rotor不同)。 我使用相邻的案例在我的机器上复制了您的结果:
然后我还使用了非相邻的case表达式:
有趣的是,二叉树搜索比CIL开关指令显示得快一点(可能不是统计上的)。 布莱恩,你已经使用了"常数"这个词,从计算复杂性理论的角度来看,它有一个非常明确的含义。虽然简单的相邻整数示例可能产生被认为是o(1)(常量)的cil,但稀疏示例是o(对数),聚集示例介于两者之间,而小示例是o(n)(线性)。 这甚至不能解决字符串情况,在这种情况下,静态 如果您检查C语言规范(而不是CIL规范)您会发现"15.7.2 switch语句"没有提到"常量时间",或者底层实现甚至使用CIL switch指令(要非常小心地假设这类情况)。 在一天结束的时候,在现代系统中,C转换成整数表达式是一个亚微秒的操作,通常不值得担心。 当然,这些时间将取决于机器和条件。我不会关注这些计时测试,我们所讨论的微秒持续时间与正在运行的任何"真正的"代码相比都相形见绌(而且您必须包含一些"真正的代码",否则编译器将优化分支),或者系统中的抖动。我的答案是基于使用IL DASM检查C编译器创建的CIL。当然,这不是最终的结果,因为CPU运行的实际指令是由JIT创建的。 我已经检查了在我的x86机器上实际执行的最终CPU指令,并且可以确认一个简单的相邻设置开关执行如下操作:
如果二叉树搜索包含:
这是我最初的帖子,引起了一些争论…因为它是错误的:
实际上,C switch语句并不总是一个常量时间分支。 在某些情况下,编译器将使用CIL switch语句,该语句实际上是使用跳转表的常量时间分支。然而,在伊万·汉密尔顿指出的少数情况下,编译器可能会完全生成其他东西。 通过编写各种C switch语句、一些稀疏语句、一些密集语句以及使用ildasm.exe工具查看结果CIL,实际上很容易验证这一点。 首先想到的是历史原因: 由于大多数C、C++和Java程序员不习惯拥有这样的自由,所以他们不需要这些自由。 另一个更为有效的原因是,语言复杂性会增加: 首先,应该将对象与 此外,允许打开对象会破坏关于switch语句的基本假设。管理switch语句的规则有两条,即如果允许打开对象,编译器将无法执行这些规则(请参见C版本3.0语言规范,?8.7.2):
在允许非常量case值的假设情况下,考虑下面的代码示例:
代码将做什么?如果案例陈述被重新排序怎么办?事实上,C使switch陷入非法状态的原因之一是switch语句可以任意重新排列。 这些规则是有原因的,这样程序员就可以通过查看一个case块来确定块输入的精确条件。当上述switch语句增长到100行或更多行(并且它将增长)时,这种知识是无价的。 顺便说一下,具有相同基础架构的vb允许更灵活的 大多数情况下,这些限制是因为语言设计者的缘故。基本的理由可能是与语言历史、理想或编译器设计的简化兼容。 编译器可以(并且确实)选择:
switch语句不是常量时间分支。编译器可能会找到捷径(使用散列桶等),但更复杂的情况将生成更复杂的MSIL代码,其中一些情况比其他情况提前分支。 为了处理字符串大小写,编译器将使用a.equals(b)(可能还有a.getHashCode())结束(在某个时刻)。我认为编译器使用任何满足这些约束的对象都是很麻烦的。 至于需要静态case表达式…如果case表达式不具有确定性,那么其中一些优化(散列、缓存等)将不可用。但我们已经看到,有时编译器只会选择简单化的if-else,无论如何… 编辑:lomaxx-您对"typeof"运算符的理解不正确。"typeof"运算符用于获取类型的System.Type对象(与其父类型或接口无关)。检查对象与给定类型的运行时兼容性是"is"运算符的工作。这里使用"typeof"来表示对象是不相关的。
是的,它不必这样做,而且许多语言实际上都使用动态开关语句。然而,这意味着重新排序"case"子句会改变代码的行为。 在这里,进入"转换"的设计决策背后有一些有趣的信息:为什么C switch语句设计为不允许失败,但仍然需要休息? 允许动态case表达式可能会导致诸如以下php代码之类的畸形:
坦率地说,应该使用 微软终于听到了! 现在有了C 7,您可以:
在这个话题上,根据杰夫·阿特伍德的说法,switch语句是一种编程的暴行。谨慎使用。 通常可以使用表来完成相同的任务。例如:
犹大的回答给了我一个主意。您可以使用
这允许您将行为与switch语句样式相同的类型相关联。我相信它还有一个额外的好处,那就是在编译成IL时,它被键控而不是切换样式的跳转表。 这不是原因,但C规范第8.7.2节规定了以下内容:
C 3.0规范位于:http://download.microsoft.com/download/3/8/8/388e7205-bc10-4226-b2a8-75351c669b09/csharp%20语言%20规范.doc 我同意这种观点,即使用表驱动方法通常更好。 在C 1.0中,这是不可能的,因为它没有泛型和匿名委托。新版本的C有脚手架使这项工作。拥有对象文本的符号也是有帮助的。 我认为编译器无法自动将switch语句转换为以下内容没有根本原因:
但是没有什么好处。 整型的case语句允许编译器进行一些优化: 没有重复(除非您复制了编译器检测到的大小写标签)。在您的示例中,由于继承,T不能匹配多个类型。是否应执行第一个匹配?都是吗? 编译器可以选择通过跳转表在整型上实现switch语句,以避免所有比较。如果要打开整数值为0到100的枚举,则它将创建一个包含100个指针的数组,每个switch语句一个指针。在运行时,它只是根据打开的整数值从数组中查找地址。这使得运行时性能比执行100个比较要好得多。 根据switch语句文档,如果有一种明确的方法可以将对象隐式转换为整型,那么将允许这样做。我认为您期望的行为是,对于每个case语句,它将被 我对C几乎一无所知,但我怀疑这两种语言中的任何一种都只是简单地将其作为其他语言中的开关,而没有考虑使其更通用,或者开发人员认为扩展它是不值得的。 严格地说,你完全正确,没有理由对它施加这些限制。有人可能会怀疑,原因是对于允许的情况,实现是非常有效的(如Brian Ensink(44921)),但如果我使用整数和一些随机情况(如345、-4574和1234203),我怀疑实现是非常有效的(w.r.t.if语句)。在任何情况下,允许它做任何事情(或者至少更多),并且说它只对特定的情况(比如(几乎)连续的数字)有效,这有什么害处呢? 但是,我可以想象,由于诸如lomaxx(44918)给出的原因,可能需要排除类型。 编辑:@henk(44970):如果最大限度地共享字符串,则内容相同的字符串也将成为指向相同内存位置的指针。然后,如果您可以确保在案例中使用的字符串连续存储在内存中,那么您可以非常有效地实现开关(即,执行顺序为2个比较、一个加法和两个跳转)。 我认为Henk用"禁止静态访问类型系统"这个词来形容它。 另一种选择是,在数字和字符串可以输入的地方没有顺序。因此,类型切换不能构建二进制搜索树,只能进行线性搜索。
|
最新内容
相关内容
linux循环语句命令?
linux循环语句命令?,地方,增长,数字,语句,流程,名称,工具,代码,数据,条件,Linux入门系列——awk命令详解1、其中command是真正的awk命令,-F表示嵌入式linux命令语句?
嵌入式linux命令语句?,系统,环境,基础,网络,软件,基础知识,服务,设备,管理,嵌入式,嵌入式linux系统开发详解_嵌入式linux系统介绍嵌入式Linuxpython是面向对象还是面向过程的
python是面向对象还是面向过程的,数据,代码,基础,形态,培训,术语,设计,对象,过程,语言,Python虽然是解释型语言,但从设计之初就已经是一门面向Python 炫技操作:条件语句的七种写
Python 炫技操作:条件语句的七种写法,代码,培训,工程,公共,写法,语法,例子,发烧友,操作,语句,有的人说Python入门容易,但是精通难的语言,这点我Python 条件语句
Python 条件语句,代码,语句,条件,名称,培训,信息,位置,结果,变量,括号,Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定列举Python面向对象中带双下划线的
列举Python面向对象中带双下划线的特殊方法,信息,代码,培训,对象,属性,方法,实例,字符串,里边,内容,__new__:生成实例__init__:生成实例的属性_Python面向对象的基本概念
Python面向对象的基本概念,概念,信息,位置,新增,培训,属性,鸟类,定义,对象,方法,python使用类(class)和对象(object),进行面向对象(object-oriPython之面向对象的进一步拓展
Python之面向对象的进一步拓展,信息,对象,操纵,培训,名字,方法,性质,参数,属性,定义,我们熟悉了对象和类的基本概念。我们将进一步拓展,以便能Python单条语句计时
Python单条语句计时,工具,对比,分析,时间,入口,标准,位置,网络,数据,培训,上下文管理器和timeit.timeit()方法也适合单条语句计时。除此之外,Python之什么是面向对象?
Python之什么是面向对象?,设计,流程,代码,个体,大唐,对比,培训,模子,上帝,对象,OOP(ObjectOrientedPrograming)编程是利用“类”和“对象”来Python 面向对象的软件开发
Python 面向对象的软件开发,设计,软件,分析,发展,工作,基础,代码,工具,通用,规模,很多人在学完了python的class机制之后,遇到一个生产中的问题Python 基本语句
Python 基本语句,培训,语句,条件,结果,逻辑,字符串,序列,完整性,事情,以上,1.条件语句在进行逻辑判断时,我们需要用到条件语句,Python提供了if