奇怪的可空比较行为

时间:2013-07-14 23:59:19

标签: c# linq nullable comparator

以下行为背后的理性(如果有)是什么:

int? a = null;
Console.WriteLine(1 > a); // prints False
Console.WriteLine(1 <= a); // prints False
Console.WriteLine(Comparer<int?>.Default.Compare(1, a)); // prints 1

为什么比较运算符的行为与默认的nullables比较器不同?

更奇怪:

var myList = new List<int?> { 1, 2, 3, default(int?), -1 };
Console.WriteLine(myList.Min()); // prints -1 (consistent with the operators)
Console.WriteLine(myList.OrderBy(i => i).First()); // prints null (nothing) (consistent with the comparator)

Console.WriteLine(new int?[0].Min()); // prints null (nothing)
Console.WriteLine(new int[0].Min()); // throws exception (sequence contains no elements)

1 个答案:

答案 0 :(得分:3)

<=>是提升的运算符,如果值为false,则返回null

  

对于关系运算符

     

< > <= >=

     

如果操作数类型都是非可空值类型且结果类型为bool,则存在提升形式的运算符。提升形式是通过添加一个?每个操作数类型的修饰符。如果一个或两个操作数为空,则提升的运算符将生成值false。否则,提升的运算符会解包操作数并应用基础运算符来生成bool结果。

由于比较器用于排序,因此需要总排序,其中null按定义比较小于其他每个值。这种需求优先于比较运算符的一致性。将null与任何其他值进行比较时返回0是不可能的,这会违反传递性,因此设计者必须选择发出错误,或者排序总是将null排序为比任何其他更小或更大值。在.net 1中,他们认为null小于其他所有参考类型的决定,自然这个决定延续到.net 2中的可空值类型。

这些差异与NaN在浮点上的行为非常相似。例如,NaN甚至不等于自身,并且所有比较运算符都返回false。但是当使用比较器NaN等于它自己并且小于除null之外的其他值时。

Enumerable.Min返回最小的非空值,如果序列不包含非空值,则仅返回null。使用这样的函数null通常代表一个省略的值,并且您有兴趣找到最小的实际值。