26

Does anyone have concrete information on how C# handles comparisons with Nullable<T> types when one side of the comparison is null?

As I understand from experimenting with the compiler, it seems that the comparison always returns false, but I can't find any documentation to back that up. Is this a real feature of the language (and thus something I can count on), or is this an implementation detail that might change in future versions?

In other words, does the following method returning true imply y.HasValue, and can you point me to some documentation that proves that it does?

    public bool foo(int x, int? y)
    {
        return x < y;
    }
Neil
  • 858
  • 1
  • 8
  • 13

5 Answers5

51

Does anyone have concrete information on how C# handles comparisons with Nullable types when one side of the comparison is null?

Yes - the C# language specification, section 7.3.7. In this case, it's a relational operator:

For the relation operators < > <= >= a lifted form of an operator exists if the operand types are both non-nullable 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.

There are similarly detailed sections for other operators.

When in doubt about how some aspect of the language works (and whether it's guaranteed or implementation-specific), the C# language specification should be your first port of call.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    To download spec for reading: http://www.microsoft.com/download/en/details.aspx?id=7029 – Anthony Pegram Feb 29 '12 at 22:15
  • This part of section 4.1.10 of the spec also helped me understand all this: "Implicit conversions are available [...] from T to T?." – andrej351 Jan 22 '14 at 01:54
  • Jon, this may be a long shot, but do you happen to know ***why***, for the `<=` and `>=` operators, "*The lifted operator produces the value `false` if one or both operands are `null`*"? It seems odd to me that `(null == null) == true`, yet `(null <= null) == false`. – Rufus L Feb 22 '18 at 01:06
7

If one of the values is null, the comparison will be false (except for !=)

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.

MSDN Source

Brandon
  • 68,708
  • 30
  • 194
  • 223
  • I don't know if the results are different. However, that quote is dealing with comparing two Nullable types. – Joe Feb 29 '12 at 22:16
2

MSDN has the following to say on the matter:

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)."

http://msdn.microsoft.com/en-us/library/2cf62fcy(v=vs.100).aspx

Here are the provided code examples:

int? num1 = 10;
int? num2 = null;
if (num1 >= num2)
{
    Console.WriteLine("num1 is greater than or equal to num2");
}
else
{
    // This clause is selected, but num1 is not less than num2.
    Console.WriteLine("num1 >= num2 returned false (but num1 < num2 also is false)");
}

if (num1 < num2)
{
    Console.WriteLine("num1 is less than num2");
}
else
{
    // The else clause is selected again, but num1 is not greater than
    // or equal to num2.
    Console.WriteLine("num1 < num2 returned false (but num1 >= num2 also is false)");
}
if (num1 != num2)
{
    // This comparison is true, num1 and num2 are not equal.
    Console.WriteLine("Finally, num1 != num2 returns true!");
}
// Change the value of num1, so that both num1 and num2 are null.
num1 = null;
if (num1 == num2)
{
    // The equality comparison returns true when both operands are null.
    Console.WriteLine("num1 == num2 returns true when the value of each is null");
}
Brandon
  • 308
  • 1
  • 2
  • 10
0

If there isn't a specific CompareTo implemented, then my research tells me that the object will use the CompareTo(object). In the case of an int, you can compare to an int or an object. In this case, it only checks to see if the object is null or not. Here's a link to the int CompareTo(object), it details the reason for results of comparing an int and an object.

http://msdn.microsoft.com/en-us/library/system.int32.aspx

I can't find anything for sure, but I don't see anything that indicates that the .NET framework was extended to include a CompareTo method for the System.Nullable<T> for each <T>.

If it were my code, I'd protect myself and extend the Int class to include a CompareTo.

urbadave
  • 231
  • 1
  • 3
  • 9
0

I know I'm late, but I'll throw my two cents in.

If memory serves, the rules for a comparer are as follows:

  • If x and y are null, return 0 (they're equal).
  • If x is null, and y is not, return -1 (x is less than y).
  • If x is not null, and y is null, return 1 (x is greater than y).

For all non-null values:

  • When the value of x evaluates to less than y, return -1.
  • When the value of x evaluates y, return 0.
  • When the value of x evaluates to greater than y, return 1.

For all intents and purposes, a Nullable<T> evaluates to null when it has no value. So the rules are essentially the same. At least, that's how I've written my comparers. If I'm doing it wrong, then, holy god, I'm doing it wrong, and I sure hope someone tells me how to fix it!!

Mike Hofer
  • 16,477
  • 11
  • 74
  • 110