2013-08-12 3 views
2

Небольшой вопрос, только для понимания: у меня есть два значения с нулевым значением. Я зачитал время создания и время обновления, оба могут быть заполнены. Поэтому я хочу проверить, что будет дальше:? Обработка конструктора с нулевыми типами

lastChangedIndrole = (tmpCreate > tmpUpdate ? tmpCreate : tmpUpdate); 

Но здесь случаются некоторые странные вещи. Я ожидаю, что вы ошиблись, когда f.e. tmpUpdate имеет значение null, но, похоже, что-то возвращает, но не значение кортежа, а только второе, в моем примере обновление.

Есть ли что-нибудь, что я не понимаю? Я думаю, что код проверяет милисекунды до 1900 года, и если есть нулевое значение, возникает ошибка. Но этого не происходит. Это какая-то магия, которую я не понимаю?

P.S. : Есть ли специальное слово для? конструктор, такой как IIF в vb? Трудно что-то искать.

Спасибо и хороший старт в неделю

Matthias

+0

* Почему бы вам ожидать, что вы выбрали исключение? Обратите внимание, что в коде, о котором вы говорите, нет конструктора. Вы просто имели в виду «условный оператор» вместо «конструктора»? –

+0

Вы также можете быть заинтересованы в проверке того, являются ли значения «null» или «DateTime.MinValue», важно убедиться, что данные действительны до назначения результата операций другой переменной (что приводит к появлению другого странного поведения и затрудняет отлаживать). – glautrou

+0

Я думаю, вы хотели использовать слово «конструкт», а не «конструктор», поскольку последнее слово имеет особое значение в .NET и C# (и, действительно, много языков программирования), тогда как «конструкция» означает что-то собранное из меньших частей , или утверждение/предложение, построенное путем сборки терминов и идей. –

ответ

1

Вы можете сравнить два DateTime? объектов, но большая часть времени, когда по крайней мере один из операндов null, результат будет false.

Например:

DateTime? today = DateTime.Today; 
DateTime? yesterday = DateTime.Today.AddDays(-1); 
DateTime? nodate = null; 
DateTime? nodate2 = null; 

Console.WriteLine(today > yesterday); //true 
Console.WriteLine(today < yesterday); //false 

Console.WriteLine(today > nodate); //false 
Console.WriteLine(today == nodate); //false 
Console.WriteLine(today < nodate); //false 

Console.WriteLine(nodate > yesterday); //false 
Console.WriteLine(nodate == yesterday); //false 
Console.WriteLine(nodate < yesterday); //false 

Console.WriteLine(nodate > nodate2); //false 
Console.WriteLine(nodate == nodate2); //true - this is the exception 
Console.WriteLine(nodate < nodate2); //false 

Я бы рекомендовал избегать слишком умен, и быть более явными в коде:

if (tmpUpdate.HasValue) 
{ 
    if (tmpCreate.HasValue) 
    { 
     lastChangedIndrole = (tmpCreate > tmpUpdate ? tmpCreate : tmpUpdate); 
    } 
    else 
    { 
     lastChangedIndrole = tmpUpdate; 
    } 
} 
else 
{ 
    if (tmpCreate.HasValue) 
    { 
     lastChangedIndrole = tmpCreate; 
    } 
    else 
    { 
     lastChangedIndrole = null; 
    } 
} 
+0

Спасибо, я просто удостоверяюсь, что значения не равны нулю, когда я проверяю их, поэтому я не могу справиться с этими проблемами. –

3

Обнуляемые типы будучи нулевым кидает исключение при Nullable.Value чтения. Но он не будет генерировать исключение при компиляции, это даст неожиданные результаты, хотя (сравнение null с ненулевым значением никогда не возвращает true).

После сниппает проиллюстрирует проблему

DateTime? dt1 = null; 
DateTime? dt2 = DateTime.Now; 

bool b1 = dt2 > dt1;//false(we expect true here) 
bool b2 = dt2 < dt1;//false 
bool b3 = dt2 == dt1;//false 

Это поведение документировано Here

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

3

C# приподнимает < и > операторы над обнуляемых типов, и они возвращаются false, если один из аргументов является недействительным.

Поэтому tmpCreate > tmpUpdate оценивается в false, если tmpCreate или tmpUpdate - null.

Он описан в спецификации:

7.3.7 Приподнятых операторы

• Для операторов отношений <> < => = поднятая форма оператора существует, если операнд типы - это типы с нулевыми значениями и если тип результата равен bool. Поднятая форма построена по , добавив сингл? модификатора для каждого типа операнда. Поднятый оператор создает значение false, если один или оба операнда равны нулю. В противном случае снятый оператор разворачивает операнды и применяет базовый оператор для получения результата bool.

+0

'((int?) null) == ((int?) null)' == 'true' , Я ненавижу сравнения с нулевым значением :-) Создание таблиц истинности для них - это серьезный уровень головной боли. – xanatos

+0

@xanatos - Да, вы правы насчет '=='. Я удалил его, поскольку он не имеет отношения к этому вопросу. – Lee

+0

Интересно ... '<=' and '> =' полностью сняты ... Итак, 'null == null', но!' Null <= null' – xanatos

1

Если сравнить NULLABLE значения, либо к другим обнуляемым значениям, или к значениям, не связанным с нулевым значением, операторы непустых типов «сняты» и, следовательно, также применимы к их нулевым аналогам.

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

Вот LINQPad пример:

void Main() 
{ 
    int? a = 10; 
    int? b = null; 

    (a > b).Dump(); 
    (b > a).Dump(); 
    (a == b).Dump(); 
    (a != b).Dump(); 
} 

Выход:

False 
False 
False 
True 

Как вы можете видеть, при сравнении двух NULLABLE Интс, где один является null, только операторы равенства дает ожидаемый результат.

Если мы делаем a переменного не-обнуляемый INT:

int a = 10; 

, но в остальном сохранить код, то он производит те же самые результаты.

Что делать, если оба значения равны нулю?

int? a = null; 
int? b = null; 

Выдает:

False 
False 
True 
False 

Вывод:

  • Операторы равенства (== и !=) правильно обрабатывать null с с обнуляемых типов
  • Меньше или больше операторов нет, они возвратят false, если один из операндов null, даже если вы переключите сравнение. В принципе, 10 не меньше или больше null.

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

1

Используйте ^ (xor), чтобы проверить, действительно ли одно условие истинно (равно нулю), а затем ??, чтобы вернуть первое непустое значение. Если оба значения не являются нулевыми, используйте существующее выражение.

if (tmpCreate == null^tmpUpdate == null) 
    lastChangedIndrole = tmpCreate ?? tmpUpdate; 
else 
    lastChangedIndrole = (tmpCreate > tmpUpdate ? tmpCreate : tmpUpdate); 

Но вы можете также выбрать, чтобы присвоить первое ненулевое значение напрямую, а затем переписать его, если tmpUpdate больше, чем значение:

lastChangedInRole = tmpCreate ?? tmpUpdate; 
if (tmpUpdate > lastChangedInRole) 
    lastChangedInRole = tmpUpdate; 

(Обоснование: Если только один имеет значение, сравнение всегда будет ложным и не нулевое значение будет присвоено с помощью ??, в противном случае tmpCreated будет присвоен и только необходимое, чтобы сравнить его с tmpUpdate.)

1

Используйте^(XOR), чтобы проверить, если ровно один кондицион (равно нулю), то? для возврата первого непустого значения. Если оба значения не являются нулевыми, используйте существующее выражение.

if (tmpCreate == null^tmpUpdate == null) lastChangedIndrole = tmpCreate ?? tmpUpdate; else lastChangedIndrole = (tmpCreate> tmpUpdate? TmpCreate: tmpUpdate);

Смежные вопросы