Reputation: 3483
small question, just for understanding: I have 2 nullable datetimes. I read out the create time and the update time, both can be filled. So I want to check which is later:
lastChangedIndrole = (tmpCreate > tmpUpdate ? tmpCreate : tmpUpdate);
But here happen some strange things. I would expect to throw a error when f.e. tmpUpdate is null, but it seem to return something, but not the corret value but just the second, in my example the update.
Is there anything I dont understand? I'd think the code checks the miliseconds to 1900 and if there is a null value an error gets thrown. But this doesnt happen. Is that some magic I dont understand?
P.S. : Is there a special word for the ? constructor like IIF in vb? It's hard to search something.
Thanks and a good start in the week
Matthias
Upvotes: 4
Views: 4903
Reputation: 15086
Use ^ (xor) to check if exactly one condition is true ( equals null) then ?? to return the first not-null value. If both are not null use your existing expression.
if (tmpCreate == null ^ tmpUpdate == null) lastChangedIndrole = tmpCreate ?? tmpUpdate; else lastChangedIndrole = (tmpCreate > tmpUpdate ? tmpCreate : tmpUpdate);
Upvotes: 1
Reputation: 15086
Use ^
(xor) to check if exactly one condition is true (equals null) then ??
to return the first not-null value. If both are not null use your existing expression.
if (tmpCreate == null ^ tmpUpdate == null)
lastChangedIndrole = tmpCreate ?? tmpUpdate;
else
lastChangedIndrole = (tmpCreate > tmpUpdate ? tmpCreate : tmpUpdate);
But you could also choose to assign the first non-null value directly and then overwrite it if tmpUpdate is larger than the value:
lastChangedInRole = tmpCreate ?? tmpUpdate;
if (tmpUpdate > lastChangedInRole)
lastChangedInRole = tmpUpdate;
(Rationale: If only one has a value, the comparison will always be false and the non null value will be assigned using ??
, otherwise the tmpCreated
will be assigned and it is only neccessary to compare it to tmpUpdate
.)
Upvotes: 1
Reputation: 144176
C# lifts the <
and >
operators over nullable types, and they return false
if one of the arguments is null.
Therefore tmpCreate > tmpUpdate
evaluates to false
if tmpCreate
or tmpUpdate
are null.
It is described in the specification:
7.3.7 Lifted operators
• For the relational operators < > <= >= a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is bool. The lifted form is constructed by adding a single ? modifier to each operand type. The lifted operator produces the value false if one or both operands are null. Otherwise, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.
Upvotes: 3
Reputation: 73492
Nullable types being null throws exception when Nullable.Value
read. But it won't throw exception when compparing it will give unexpected results though(Comparing null
with non-null value never returns true).
Following snippet will illustrate the problem
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
This behavior is documented Here
When you perform comparisons with nullable types, if the value of one of the nullable types is null and the other is not, all comparisons evaluate to false except for != (not equal). It is important not to assume that because a particular comparison returns false, the opposite case returns true. In the following example, 10 is not greater than, less than, nor equal to null. Only num1 != num2 evaluates to true.
Upvotes: 3
Reputation: 391456
When you compare nullable values, either to other nullable values, or to non-nullable values, operators on the non-nullable types are "lifted", and thus also apply to their nullable counterparts.
However, special handling will handle the case where either or both are null.
Here's a LINQPad example:
void Main()
{
int? a = 10;
int? b = null;
(a > b).Dump();
(b > a).Dump();
(a == b).Dump();
(a != b).Dump();
}
Output:
False
False
False
True
As you can see, when comparing two nullable ints, where one is null
, only the equality operators produces the expected result.
If we make the a
variable a non-nullable int:
int a = 10;
but otherwise keep the code, then it produces the exact same results.
What if both are null?
int? a = null;
int? b = null;
Produces:
False
False
True
False
Conclusion:
==
and !=
) correctly handle null
s with nullable typesfalse
if one of the operands is null
, even if you switch the comparison around. Basically, 10
is neither less than or greater than null
.If you try to read the .Value
property of a null
nullable type value, it will throw an exception, but the operators do not go directly for the .Value
property, but check the .HasValue
property first, and then handle these cases before attempting the actual comparison.
Upvotes: 1
Reputation: 30902
You can compare two DateTime?
objects, but most of the time, when at least one of the operands is null
, the result will be false
.
For example:
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
I would recommend avoiding being too clever, and being more explicit in the code:
if (tmpUpdate.HasValue)
{
if (tmpCreate.HasValue)
{
lastChangedIndrole = (tmpCreate > tmpUpdate ? tmpCreate : tmpUpdate);
}
else
{
lastChangedIndrole = tmpUpdate;
}
}
else
{
if (tmpCreate.HasValue)
{
lastChangedIndrole = tmpCreate;
}
else
{
lastChangedIndrole = null;
}
}
Upvotes: 2