.net 编译和运行时不可为null的DateTime(in)相等吗?

.net 编译和运行时不可为null的DateTime(in)相等吗?,.net,datetime,compilation,.net,Datetime,Compilation,基于,当这段代码编译并运行时,我(以及上述问题中的OP)感到困惑: DateTime dateTime = new DateTime(); bool isFalse = dateTime == null; bool isTrue = dateTime != null; 请注意,dateTime变量不可null。当我将鼠标悬停在等号上时,它告诉我它的签名是boolDateTime.operator==(DateTime dateTime1,DateTime dateTime2),并且null是

基于,当这段代码编译并运行时,我(以及上述问题中的OP)感到困惑:

DateTime dateTime = new DateTime();
bool isFalse = dateTime == null;
bool isTrue  = dateTime != null;
请注意,
dateTime
变量不可
null
。当我将鼠标悬停在等号上时,它告诉我它的签名是bool
DateTime.operator==(DateTime dateTime1,DateTime dateTime2)
,并且
null
是可为null的

编译器在这里做什么?它是否使用某种隐式转换


我发现了类似的问题,但它只是回避了问题,并没有解释编译器为什么要这样做。

根据以下规则:

形式为
x op y
的操作,其中
op
是可重载的二进制运算符,
x
x
类型的表达式,
y
y
类型的表达式,其处理如下:

  • 确定由
    X
    Y
    为操作
    运算符op(X,Y)
    提供的候选用户定义运算符集。该集合由
    X
    提供的候选运算符和
    Y
    提供的候选运算符的并集组成,每个运算符都使用候选用户定义运算符的规则确定。[……]
说:

对于
T0
中的所有
运算符op
声明以及此类运算符的所有提升形式
,如果至少有一个运算符适用于参数列表
A
,则候选运算符集由
T0
中的所有此类适用运算符组成

:

提升运算符允许对不可空值类型进行操作的预定义和用户定义的运算符也与这些类型的可空形式一起使用。提升操作器由满足特定要求的预定义和用户定义的操作器构成,如下所述:

[……]

  • 对于相等运算符
    ===
    如果操作数类型都是不可为空的值类型,并且结果类型是
    bool
    ,则存在运算符的提升形式。提升形式是通过向每个操作数类型添加单个
    修饰符来构造的。提升运算符认为两个空值相等,一个空值不等于任何非空值。如果两个操作数都不为空,则提升运算符将展开操作数并应用基础运算符以生成
    bool
    结果
因此编译器查看操作数
DateTime
null
,找到用户定义的,并将其提升到
==(DateTime?,DateTime?)
。由于
DateTime
null
都可以隐式转换为
DateTime?
,因此此提升运算符适用,并最终被选为最佳候选运算符