C# 可空相等操作,为什么 null <= null 解析为 false?

标签 c# .net null comparison-operators

<分区>

为什么是.NET

null >= null

解析为假,但是

null == null 

解析为真?

换句话说,为什么 null >= null 不等同于 null > null || null == null?

有官方的答案吗?

最佳答案

此行为在 C# 规范 ( ECMA-334 ) 的第 14.2.7 节中定义(我已突出显示相关部分):

For the relational operators

< > <= >=

a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is bool. The lifted form is constructed by adding a single ? modifier to each operand type. The lifted operator produces the value false if one or both operands are null. Otherwise, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

特别是,这意味着通常的关系法则不成立; x >= y并不意味着 !(x < y) .

血淋淋的细节

有些人问为什么编译器认为这是 int? 的提升运算符首先。我们来看一下。 :)

我们从 14.2.4“二元运算符重载决议”开始。这详细说明了要遵循的步骤。

  1. 首先,检查用户定义的运算符的适用性。这是通过检查由 >= 的每一侧的类型定义的运算符来完成的。 ...这提出了一个问题,即 null 的类型是什么?是! null在给定一个之前,文字实际上没有任何类型,它只是“空文字”。按照 14.2.5 下的说明,我们发现这里没有合适的运算符,因为 null 文字没有定义任何运算符。

  2. 此步骤指示我们检查预定义运算符集的适用性。 (本节也排除了枚举,因为两边都不是枚举类型。)相关的预定义运算符在 14.9.1 到 14.9.3 节中列出,它们都是原始数字类型的运算符,以及提升版本这些运算符(注意此处不包括 string s 运算符)。

  3. 最后,我们必须使用这些运算符和 14.4.2 中的规则执行重载决议。

实际上执行这个决议会非常乏味,但幸运的是有一个捷径。在 14.2.6 下有一个重载决议结果的信息示例,其中指出:

...consider the predefined implementations of the binary * operator:

int operator *(int x, int y);
uint operator *(uint x, uint y);
long operator *(long x, long y);
ulong operator *(ulong x, ulong y);
void operator *(long x, ulong y);
void operator *(ulong x, long y);
float operator *(float x, float y);
double operator *(double x, double y);
decimal operator *(decimal x, decimal y);

When overload resolution rules (§14.4.2) are applied to this set of operators, the effect is to select the first of the operators for which implicit conversions exist from the operand types.

由于两边都是null我们可以立即丢弃所有未解除的运算符。这给我们留下了所有原始数字类型的提升数字运算符。

然后,使用先前的信息,我们选择第一个存在隐式转换的运算符。由于 null 文字可隐式转换为可空类型,并且 int 存在可空类型,我们从列表中选择第一个运算符,即 int? >= int? .

关于C# 可空相等操作,为什么 null <= null 解析为 false?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4730648/

相关文章:

java - 为什么我的 Spring @Autowired 字段为空?

c# - 这把锁有什么问题?

c# - String.format 慢,需要更快的替代品

c# - DataAnnotations问题

c# - 使用 Windsor 注册特定程序集和命名空间中的所有服务?

c# - 将具有键值属性的对象 [] 映射到对象的属性,而无需使用巨大的讨厌开关

java - 如何在非null值上设置editText

c# - 有没有办法将方法标记为确保 T 不为空?

c# - 为什么必须用属性 [serializable] 标记一个类?

c# - 批量处理,更好的方法?