如果(1 == null)不应该导致错误?

use*_*769 9 c#

Int32struct没有为==运算符定义运算符重载方法,那么为什么代码不会导致编译时错误:

if(1 == null) ... ;
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 26

我们在这里退一步吧.这个问题令人困惑,到目前为止,答案并不清楚这里发生了什么.

不应该if(1 == null)导致错误?

不,这是合法的,虽然愚蠢.

编译器如何处理像"=="这样的运算符?它通过应用重载决策算法来实现.

我们必须确定的第一件事是这是"用户定义的"等式运算符还是"内置"等式运算符.左侧是内置类型.右侧根本没有类型.这些都不是用户定义的类型.因此,不会考虑用户定义的运算符.只考虑内置运营商.

一旦我们知道,问题是"将考虑哪些内置运营商?" 内置运算符在规范的第7.10节中描述.它们是int,uint,long,ulong,decimal,float,double,任何枚举类型,bool,char,object,string和任何委托类型的相等运算符.

值类型上的所有相等运算符也具有"可提升"形式,该形式采用可为空的值类型.

我们现在必须确定哪些运营商适用.要适用,必须从双方隐式转换为运营商的类型.

没有从int到任何枚举类型,bool,字符串或任何委托类型的隐式转换,所以这些都会从考虑中消失.

(没有从int到uint,ulong等的隐式转换,但由于这是一个文字的转换,因此存在从1到uint,ulong等的隐式转换)

没有从null到任何非可空值类型的隐式转换,因此这些都会消失.

那会留下什么?这使运算符留在object,int?,long?,uint?,ulong?,double?,float ?, decimal?和char?剩下的可空类型.

我们现在必须确定哪些剩余的适用候选人是唯一的"最佳"运营商.如果运算符的操作数类型更具体,则运算符优于另一运算符."对象"是最不具体的类型,因此被删除.显然,每个可以为null的int都可以转换为可空的long,但并非每个可空的long都可以转换为nullable int,因此nullable long比nullable int更不具体.所以它被淘汰了.我们继续以这种方式消除运营商.(在无符号类型的情况下,我们应用一个特殊规则,如果int?和uint?都是选项,那么int?wins.)

我会告诉你细节; 最终,该进程将nullable int作为唯一的最佳操作数类型.

因此,您的程序被解释为if((int?)1 == (int?)null),这显然是合法的,并且始终是错误的.

Int32结构不为==运算符定义运算符重载方法

你是对的.这与任何事情有什么关系?没有它,编译器完全能够进行分析.我不明白你认为这个事实对你的问题的关系.事实是关于可以在类型上定义的方法,问题是关于重载分辨率如何选择提升的内置运算符.这两件事没有关系,因为"int"不是用户定义的类型.

  • @ user702769:值类型运算符的提升形式是可以处理null的运算符.引用相等运算符已经能够处理空值,因为引用类型始终可以为null.如果类型系统被设计为支持不可空的引用类型,那么当然也必须在引用类型上提升运算符.但事实并非如此.下次设计类型系统时请记住这一点:从第一天起烘焙值和参考类型的不可空性! (4认同)