Подтвердить что ты не робот

Является ли значение null в .NET DateTime гарантированным, чтобы быть меньше реальной стоимости?

Возможно, мой Google-Фу меня не сбил, но мне не удалось определить, будет ли сравнивать значение nullable в .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
}
4b9b3361

Ответ 1

Это поведение гарантируется спецификацией С#. Результатом < для значений NULL-значений является false, если любой из них null. С другой стороны, типы ссылок могут иметь различное поведение.

Тем не менее я бы не рекомендовал использовать это. Трудно понять этот код. Я бы предпочел явную проверку null или просто логический флаг isFirstElement вместо того, чтобы использовать нулевое значение.

7.2.7 Поднятые операторы

Поднятые операторы допускают предопределенные и определяемые пользователем операторы, которые работают с типами значений, не допускающих нулевых значений, которые также могут использоваться с типами NULL для этих типов. Поднятые операторы построены из предопределенных и определяемых пользователем операторов, которые отвечают определенным требованиям, как описано в следующем:

...

  • Для реляционных операторов     < > <= >=
    если тип операндов является невообразимыми типами значений, и тип результата равен bool. Поднятая форма строится путем добавления единственного модификатора ? к каждому типу операнда. Оператор lifted создает значение false, если один или оба операнда null. В противном случае снятый оператор разворачивает операнды и применяет основной оператор для получения результата bool.

(Цитируется по языковой версии С# версии 3.0)

Ответ 2

Цитата из MSDN:

Когда вы выполняете сравнения с типами NULL, если значение одного нулевых типов - null, а другой - нет, все сравнения оценивать значение false, кроме != (не равно). Важно не предположим, что, поскольку конкретное сравнение возвращает false, противоположный случай возвращает true. В следующем примере 10 не больше, меньше или равно нулю. Только num1 != num2имеет значение true.

Сравнение равенств двух типов с нулевым значением, которые равны нулю, равно true.

Ответ 3

В этом случае он никогда не будет true. Сравнение значений с нулевым значением, когда одно из значений null всегда производит ложь. Следовательно, сравнение if здесь никогда не будет истинным, а latest_item никогда не будет установлено значение

Ответ 4

Независимо от правил компиляции, код не очень читабельен. Вы должны явно явно проверить нуль (IMO):

if (latest_tstamp == null)

Ответ 5

Это не гарантируется для работы для всех типов, поскольку оператор < может быть переопределен, чтобы иметь смысл для определенного класса, и этот код может не принимать во внимание. Для стандартных операторов для 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;
    }
}

Я согласен с другим ответом здесь, что, хотя ваш код может работать, было бы лучше иметь явную проверку нулей.