奇怪的可空比较行为

Cha*_*ion 5 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
Run Code Online (Sandbox Code Playgroud)

为什么比较运算符的行为与默认的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)
Run Code Online (Sandbox Code Playgroud)

Cod*_*aos 3

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

对于关系运算符

< > <= >=

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

由于比较器用于排序,因此它们需要总排序,null根据定义,比较器小于所有其他值。这种需要优先于比较运算符的一致性。与任何其他值进行比较时返回 0null是不可能的,这会违反传递性,因此设计人员必须选择要么发出错误,要么排序始终排序null为小于或大于任何其他值。在 .net 1 中,他们决定null比引用类型中决定的其他所有内容都要小,并且自然地,该决定会延续到 .net 2 中的可空值类型。

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

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