Является ли значение 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
}
Ответы
Ответ 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;
}
}
Я согласен с другим ответом здесь, что, хотя ваш код может работать, было бы лучше иметь явную проверку нулей.