17

Possible Duplicate:
C# okay with comparing value types to null

If I try to assign null to a non-nullable type in C#:

System.DateTime time = null;

I'll get a compile-time error:

error CS0037: Cannot convert null to 'System.DateTime' because it is a non-nullable value type

which makes sense. But if compare the same type against null:

System.DateTime time = obtainFromSomewhere();
if( time == null ) {
    //whatever;
}

there's no compile-time error. This doesn't make sense to me - if I can't assign null then why would it ever be null?

Why am I allowed to compare a non-nullable type with null?

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • 2
    Because the statement itself is valid. You can always check an object for null. – halfdan Apr 19 '11 at 08:10
  • 1
    Isn't it valid because of allowed implicit convertion of non-nullable types to nullabe? – username Apr 19 '11 at 08:39
  • 4
    See [Comparing structs to null](http://stackoverflow.com/questions/2022425/comparing-structs-to-null) and [C# okay with comparing value types to null](http://stackoverflow.com/questions/1972262/c-okay-with-comparing-value-types-to-null) where Eric Lippert already provided an excellent answer (so far none of the answers here seems correct). – Dirk Vollmar Apr 19 '11 at 08:40
  • 2
    @0xA3: Brian's answer is essentially correct, but yes, you are correct in that this is a duplicate. @sharptooth: if you compare a built-in type like int to null, the compiler gives a warning that the comparison is always false, but does not do so for lifted user-defined equality operators; this is a shortcoming of the compiler. I apologize for the lack of a warning; we really should add one here. – Eric Lippert Apr 19 '11 at 15:37

5 Answers5

18

The reason this works for DateTime, is because DateTime defines it own == operator. Because it does so, it gets a lifted version of the operator which may be used with DateTime?. Since both DateTime and null may be implicitly converted to DateTime?, the comparison compiles but will always evaluate to false at runtime.

Thanks to Matt Ellen for pointing out the fact that my original answer didn't cover the example in the question.

Brian Rasmussen
  • 114,645
  • 34
  • 221
  • 317
  • 2
    but In sharptooth's example, there is no type parameter, so it should not compile. A compile time error should occur unless both operands are reference-types or `null`. – Matt Ellen Apr 19 '11 at 08:32
  • In fact just above your quote is this: "The predefined reference type equality operators do not permit value type operands to be compared. Therefore, unless a struct type declares its own equality operators, it is not possible to compare values of that struct type." – Matt Ellen Apr 19 '11 at 08:48
5

It's due to Boxing.

DateTime can be boxed as object and thus it becomes a reference which can be compared with null (though it will always be false).

However, an object (null) can't be unboxed back to DateTime, thus it can't be assigned to DateTime.

Example: you could do

object now = DateTime.Now;
bool isNull = now == null

EDIT: As Brian Rasmussen pointed out, I was wrong with the boxing theory. Boxing would only occur if explicitly casted to object like in my example or in (object)DateTime.Now == null.

František Žiačik
  • 7,511
  • 1
  • 34
  • 59
2

There is an implicit conversion to a nullable type since .NET 2.0 (See what Eric Lippert said here).

The compiler gives you the following warning that indicates that a conversion takes place:

C:\>c:\windows\Microsoft.NET\Framework\v2.0.50727\csc test.cs
Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.4927
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727

test.cs(16,12): warning CS0464: Comparing with null of type 'int?' always produces 'false'

In .NET 1.1 which didn't have nullable types your code sample would not have been legal:

C:\>c:\windows\Microsoft.NET\Framework\v1.1.4322\csc test.cs
Microsoft (R) Visual C# .NET Compiler version 7.10.3052.4
for Microsoft (R) .NET Framework version 1.1.4322
Copyright (C) Microsoft Corporation 2001-2002. All rights reserved.

test.cs(12,13): error CS0019: Operator '==' cannot be applied to operands of type 'System.DateTime' and ''
Community
  • 1
  • 1
Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
1

it should be a nullable type :

System.DateTime? time = null;

your code should appear like this :

System.DateTime? time = obtainFromSomewhere();
if( time.HasValue ) {
    //use time.Value;
}

but remember your obtainFromSomewhere function should return a DateTime? type.

Farzin Zaker
  • 3,578
  • 3
  • 25
  • 35
1

In my opinion, this is allowed, because NULL is not a real value from no type.

It is good some code like below is allowed :

System.DateTime time = obtainFromSomewhere(); // allways a date
System.DateTime? otherTime = obtainFromSomewhereElse(); // null if nothing planned

if (time == otherTime)
{
    // match
    ...
}

What would we do without null anyway ?

Community
  • 1
  • 1
Larry
  • 17,605
  • 9
  • 77
  • 106