为什么short null值转换为int null值与null进行比较?

当我比较可为空的short值时,编译器首先将它们转换为整数以与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版本,包括.NET 4。

我在这里错过了什么? 对于HasValue检查,这种双重转换的原因是什么?

跟进

我期望编译器要做的就是用.HasValue做一个简单的检查, if (cTestA.HasValue){} 。 至less这是我发现这个转换后,在我的代码中做的事情。

为什么所有这些额外的代码添加这样一个简单的testing?

Re:你最新的更新:

这是可空算术优化器中的一个错误。

可以为空的优化器将删除不必要的转换为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?(); 

优化的codegen是等价的:

 short? s = null; int? x; x = s.HasValue ? new int?((int)s.Value + 1) : new int?(); 

但是,优化器包含一个错误; 我们不删除不必要的平等转换。

感谢您引起我的注意; 我们将修复Roslyn 。 实际上,我将在接下来的几周内为Roslyn编写可优化的优化器。

更新:我写了那个优化器,如果你对它的工作原理感兴趣,我写了一系列关于它的文章,从这里开始:

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可以完全表示两个操作数的所有可能的值。 然后使用typesT的精度执行操作,结果的types是T(或关系运算符为bool)。 不允许一个操作数是longtypes,另一个操作数是二元运算符types的ulong。

使用short的操作被提升为int,并且这些操作被取消为可空的对应。 (这导致了第7.3.6.2和7.3.7节)


好吧,这是由devise,但仍然不明白为什么他们这样做,他们已经优化了string添加太多,为什么留下数字单独和添加更多的代码,这个简单的比较

这只是语言devise的方式,要考虑现代build筑的优化。 不是特别在这方面,而是考虑Eric Lippert在这里所说的话

在C#中,算术从来就不是简单的。 算术可以用int,uint,longs和ulong来完成,但算术从来就不是简单的。 Shorts推广到int,算术是用int整理的,因为就像我之前说过的那样,绝大多数的算术计算都适合int。 绝大多数不适合于短期。 短的算术在现代硬件上可能会比较慢,而这个硬件是针对整数进行优化的,短算术不占用更less的空间; 它将在芯片上以整数或长整数完成。


您的最新更新:

我希望编译器做的是用.HasValue做一个简单的检查,如果(cTestA.HasValue){}至less这是我发现这个转换后在代码上做的事情。 所以这是我真的不明白为什么不这样做简单的想法,但添加所有这些额外的代码。 编译器总是试图优化代码 – 为什么在这里避免简单的.HasValue检查。 我很想念这里的东西

我将不得不推迟一位编译器专家,说为什么他们select去转换,而不是直接的HasValue检查,除非说可能只是一个操作顺序。 语言规范说二进制运算符操作数被提升,这就是他们在提供的代码片段中所做的。 语言规范后来说,用x == null检查,其中x是一个可为空值的types,可以转换为!x.HasValue ,这也是他们所做的。 在你已经提交的编译代码中,数字提升仅仅比可以为空的行为先例。

至于编译器总是试图优化代码,专家再次澄清,但事实并非如此。 有可能做的优化,而其他的则可能是抖动。 编译器或者抖动的优化可能会也可能不会,这取决于它是一个debugging版本还是发行版本,不论是否附带debugging器。 毫无疑问,他们可以做出最优化的select,因为成本与收益并没有发挥作用。