为什么短null值转换为int null值以便与null进行比较
本文关键字:null 比较 int 转换 为什么 | 更新日期: 2023-09-27 18:23:52
当我比较可为null的短值时,编译器首先将它们转换为integer,以与null进行比较。例如,考虑这个简单的代码:
short? cTestA;
if (cTestA == null) { ... }
编译器将其转换为:
short? CS$0$0001 = cTestA;
int? CS$0$0002 = CS$0$0001.HasValue ? new int?(CS$0$0001.GetValueOrDefault()) : null;
if (!CS$0$0002.HasValue){ ... }
这种情况适用于包括.NET 4在内的所有.NET版本。
我在这里错过了什么?为什么只为HasValue检查而进行双重转换?
跟进
我希望编译器使用.HasValue,if (cTestA.HasValue){}
进行简单的检查。至少这是我在发现这种转换后在代码中所做的。
为什么要为这样一个简单的测试添加所有这些额外的代码?
Re:您的最新更新:
这是可为null的算术优化器中的一个错误。
当您执行以下操作时,可为null的优化器将删除对int?
的不必要转换:
short? s = null;
int? x = s + 1;
未优化的编解码器相当于:
short? s = null;
int? x;
int? temp = s.HasValue ? new int?((int)s.Value) : new int?();
x = temp.HasValue ? new int?(x.Value + 1) : new int?();
优化的编解码器相当于:
short? s = null;
int? x;
x = s.HasValue ? new int?((int)s.Value + 1) : new int?();
但是,优化器包含一个错误;我们不删除不必要的平等转换。
谢谢你引起我的注意;我们会帮罗斯林解决的。实际上,我将在接下来的几周内为Roslyn编写可为null的优化器。
更新:我确实写了那个优化器,如果你对它的工作方式感兴趣,我写了一系列关于它的文章,从这里开始:
http://ericlippert.com/2012/12/20/nullable-micro-optimizations-part-one/
参见C#4.0语言规范的第4.1.5节。特别值得关注的是:
C#支持九种积分类型:sbyte、byte、short、ushort、int、uint、long、ulong和char。[省略文本]
整型一元运算符和二进制运算符总是与有符号32位精度、无符号32位精确度、有符号64位精度,或无符号64位精度:
[省略要点]
对于二进制+,–,*,/,%,&,^,|===,!=,><,>=,并且<运算符,操作数转换为类型T,其中T是第一个可以完全表示所有可能的int、uint、long和ulong两个操作数的值。然后使用类型为T的精度,结果的类型为T(或关系运算符)。不允许一个操作数为类型long,另一个类型ulong,带有二进制运算符。
使用short的操作被提升为int,这些操作将被提升为可为null的对应操作。(这导致第7.3.6.2节和第7.3.7节)
好吧,这是设计的,但仍然不明白他们为什么这么做,他们已经优化了字符串添加了太多,为什么不考虑数字,并为这个简单的比较添加了更多的代码
这只是语言的设计方式,并考虑到现代建筑中的优化。在这种情况下并不具体,但考虑一下Eric Lippert在这里所说的话
在C#中,算术从来都不是短期完成的。算术可以用int、uint、long和ulong来完成,但算术永远不会用short来完成。Shorts提升为int,算术是用int完成的,因为正如我之前所说,绝大多数算术计算都适合int。绝大多数不适合short。在为int优化的现代硬件上,短算术可能较慢,并且短算术不会占用更少的空间;它将在芯片上以整数或整数进行。
您的最新更新:
我希望编译器做的是使用.HasValue if(cTestA.HasValue){}进行简单检查,至少这是我发现此转换后对代码所做的操作。所以我真的不明白为什么不做简单的思考,而是添加所有这些额外的代码。编译器总是试图优化代码-为什么这里要避免简单的.HasValue检查。我肯定错过了什么。。。
我将不得不听从编译器专家的意见,解释他们为什么选择进行转换而不是立即进行HasValue检查,只是说可能只是有一个操作顺序。语言规范说二进制运算符操作数是被提升的,这就是他们在提供的代码段中所做的。语言规范后来说,使用x == null
的检查(其中x是可为null的值类型)可以转换为!x.HasValue
,这也是他们所做的。在您提供的编译代码中,数字提升只是以可为null的行为为先例。
至于编译器总是试图优化代码,专家可以再次澄清,但事实并非如此。它可以进行一些优化,而其他优化则可能会受到抖动的影响。编译器或抖动可能会进行优化,也可能不会进行优化,这取决于它是调试版本还是发布版本,是否附加调试器。毫无疑问,他们可以做出一些优化,他们只是选择不这样做,因为成本与收益的对比并没有发挥出来。