18

也许我的 Google-Fu 让我失望了,但我无法确定在 .NET 中比较可空值是否总是比其他东西少。

我有一些类似的代码

MyClass findLatest(List<MyClass> items){
    DateTime? latest_tstamp = null;
    MyClass latest_item = null;
    foreach(var item in items){
        if (latest_tstamp < item.tstamp){
            latest_tstamp = item.tstamp;
            latest_item = item;
        }
    }
    return latest_item;
}

它似乎在我尝试过的少数有限情况下有效(当然item.tstamp也声明DateTime? tstamp了)。

这是有保证的行为吗?

结论(?)

根据答案(以及 Jon Skeet 的 [对另一个问题的回答]),我进行了以下检查:

if (item.tstamp != null &&
    (latest_tstamp == null || latest_tstamp < item.tstamp)){
    // do stuff
}
4

6 回答 6

23

这是 C# 规范所保证的行为。<on 可空值类型的结果是false如果它们中的任何一个是null. 另一方面,引用类型可能表现出不同的行为。

我仍然不建议使用这个。很难理解这段代码。我更喜欢显式null检查,或者只是一个布尔标志isFirstElement,而不是首先使用可空值。

7.2.7 吊运操作员

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

...

  • 对于关系运算
         <   >   <=   >=
    符,如果操作数类型都是不可为空的值类型并且结果类型是 ,则存在运算符的提升形式bool。提升形式是通过向每个操作数类型添加单个?修饰符来构造的。如果一个或两个操作数是,则提升的运算符产生值。falsenull否则,提升的运算符会展开操作数并应用底层运算符来生成bool结果。

(引自 C# 语言规范 3.0 版)

于 2012-07-11T17:06:29.780 回答
6

引用 MSDN:

当您对可空类型执行比较时,如果一个可空类型的值为空而另一个不是,则所有比较的结果都为假,除了!=(不等于)。重要的是不要假设因为特定的比较返回 false,相反的情况返回 true。在以下示例中,10 不大于、小于或等于 null。仅num1 != num2 评估为真。

两个都为 null 的可为 null 类型的相等比较计算结果为 true。

于 2012-07-11T17:03:26.673 回答
2

在这种情况下,它永远不会true。在其中一个值null始终为 false 的可空值之间进行比较。因此,if这里的比较永远不会是真的,latest_item也永远不会被设置为一个值

于 2012-07-11T17:03:13.710 回答
1

只是一个补充,你可以打电话Nullable.GetValueOrDefault()

例子:

if (dateTime1.GetValueOrDefault() < dateTime2)
  ...
于 2019-03-15T16:21:35.513 回答
0

无论编译器规则如何,代码的可读性都不是很高。您绝对应该明确地进行空值检查(IMO):

if (latest_tstamp == null)
于 2012-07-11T17:01:58.453 回答
0

这不能保证适用于所有类型,因为<可以重写运算符以对特定类有意义,并且该代码可能不考虑 null。对于 的标准运算符Nullable<T>, null 将比较小于一个值。

但是,如果您正在处理自定义类型,请考虑它们的运算符可能不会考虑空值。例如,看看这个愚蠢的例子:

void Main()
{
    Foo x = null;
    Foo y = new Foo();

    Console.WriteLine(x < y);
    Console.WriteLine(x > y);
}

class Foo 
{
    public static bool operator <(Foo lhs, Foo rhs)
    {
        if (ReferenceEquals(lhs, null))
            return false;
        return true;
    }

    public static bool operator >(Foo lhs, Foo rhs)
    {
        return false;
    }
}

我同意这里的另一个答案,即使您的代码可能有效,但进行明确的空值检查会更好。

于 2012-07-11T17:03:24.473 回答