Why can TimeSpan and Guid Structs be compared to null?

This case is covered for generics in section 7.9.6 of the C# language specification.

The x == null construct is permitted even though T could represent a value type, and the result is simply defined to be false when T is a value type.

I dug through the spec for a bit and couldn't find a more general rule. Jon's answer indicates it's a nullable promotion issue.

This rule (or a similar variation) does seem to be being applied here. If you look at the reflected output closely you'll notice the comparison isn't there. The C# compiler is apparently optimizing this comparison away and replacing it with false.

For instance, if you type the following

var x = new TimeSpan();
var y = x == null;
Console.WriteLine(x);

Then decompile it you'll see the following

var x = new TimeSpan();
var y = false;
Console.WriteLine(x);

See also: C# 3 (.NET 3.5) version of csc fails to report CS0162 for unrechable code (struct/null)

Starting with the C# 3 compiler that means it sometimes doesn't even warn you about this ;-p

Because Guid / TimeSpan etc provide ==, they fall into this trap where it doesn't warn you.


This problem was effectively introduced when nullable types were included. There's an implicit conversion from TimeSpan to TimeSpan?, and there's a comparison between TimeSpan? and the null value of that type.

The compiler issues a warning for some types which makes it clearer what it's trying to do:

int x = 10;
if (x == null)
{
    Console.WriteLine();
}

Gives this warning:

Test.cs(9,13): warning CS0472: The result of the expression is always 'false'
       since a value of type 'int' is never equal to 'null' of type 'int?'

I believe Marc Gravell and I worked out the circumstances under which the warning is given once... it's a shame it's not consistent.


It's the == operator.

The TimeSpan class has an overload of the equality operator:

public static bool operator ==(DateTime d1, DateTime d2)
{
     return (t1._ticks == t2._ticks);
}

This in itself doesn't make it possible to compare with null, but...

With the arrival of nullable types, each struct is implicitly convertible to its nullable type, so when you see something like

TimeSpan y = new TimeSpan();
if (y == null)
    return;

You don't see that this is happening:

TimeSpan y = new TimeSpan();
if ((Nullable<TimeSpan>)y == (Nullable<TimeSpan>)null)
    return;

Null gets the implicit conversion (implicit assignment?), but not all System.Object objects do:

TimeSpan y = new TimeSpan();
object o = null;
if (y == o) //compiler error
    return;

Okay, but the equality operator doesn't take nullable arguments, does it?

Well, msdn is of help here, stating:

The predefined unary and binary operators and any user-defined operators that exist for value types may also be used by nullable types. These operators produce a null value if [any of] the operands are null; otherwise, the operator uses the contained value to calculate the result.

So you effectively get a nullable implementation for each operator for free, with a fixed defined behaviour. The "contained value" mentioned above is the actual value the non-nullable operator would return.