Consider the following code:
DateTime t = DateTime.Today;
bool isGreater = t > null;
With Visual Studio 2010 (C# 4, .NET 4.0), I get the following warning:
warning CS0458: The result of the expression is always 'null' of type 'bool?'
This is incorrect; the result is always false
(of type bool
):
Now, the struct DateTime overloads the >
(greater than) operator. Any non-nullable struct (like DateTime) is implicitly convertible to the corresponding Nullable<>
type. The above expression is exactly equivalent to
bool isGreater = (DateTime?)t > (DateTime?)null;
which also generates the same wrong warning. Here the >
operator is the lifted operator. This works by returning false if HasValue
of any of its two operands is false
. Otherwise, the lifted operator would proceed to unwrap the two operands to the underlying struct, and then call the overload of >
defined by that struct (but this is not necessary in this case where one operand does not HasValue
).
Can you reproduce this bug, and is this bug well-known? Have I misunderstood something?
This is the same for all struct types (not simple types like int
, and not enum types) which overload the operator in question.
(Now if we use ==
instead of >
, everything ought to be entirely similar (because DateTime also overloads the ==
operator). But it's not similar. If I say
DateTime t = DateTime.Today;
bool isEqual = t == null;
I get no warning ☹ Sometimes you see people accidentally check a variable or parameter for null, not realizing that the type of their variable is a struct (which overloads ==
and which is not a simple type like int
). It would be better if they got a warning.)
Update: With the C# 6.0 compiler (based on Roslyn) of Visual Studio 2015, the incorrect message with isGreater
above is changed into a CS0464 with a correct and helpful warning message. Also, the lack of warning with isEqual
above is fixed in VS2015's compiler, but only if you compile with /features:strict
.
I discovered this error independently while implementing lifted operator behaviour in Roslyn, and I fixed it in Roslyn before I left.
Sorry that I didn't see this when you posted it back in October. Thanks for submitting it to Connect! And many apologies for the error; it is a long-standing error in operator semantic analysis.
Incidentally, I'll be discussing how Roslyn optimizes lifted expressions on http://ericlippert.com later this month (December 2012), so if this subject interests you, check it out:
http://ericlippert.com/2012/12/20/nullable-micro-optimizations-part-one/
You are correct: this is a bug in Visual Studio. The C# 4.0 standard (§ 7.3.7 Lifted operators) has this to say:
For the relational operators
< > <= >=
[…] The lifted operator produces the value
false
if one or both operands are null. …
And in fact, in MonoDevelop, you get the following warning instead:
The result of comparing type
System.DateTime
withnull
is alwaysfalse
.
DateTime t = DateTime.Today;
bool isGreater = (DateTime?)t > (DateTime?)null;
In this scenario what the warning is about is the t > null
. That is never going to be true. Because It can't be evaluated.
In this scenario:
bool isGreater = (DateTime?)t > (DateTime?)null;
We are evaluating (DateTime?)t > (DateTime?)null
;
Or essentially in the best case scenario t > null
; same as before. DateTime.Now can never be greater than Undefined, hence the warning.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With