9

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

I came a cross something I find strange in the C# (4.0) compiler just now.

int x = 0;
if (x == null) // Only gives a warning - 'expression is always false'
    x = 1;

int y = (int)null; // Compile error
int z = (int)(int?)null; // Compiles, but runtime error 'Nullable object must have a value.'

If you cannot assign null to an int, why does the compiler allow you to compare them (It gives a warning only)?

Interestingly, the compiler does not allow the following:

struct myStruct
{
};

myStruct s = new myStruct();
if (s == null) // does NOT compile
    ;

Why does the struct example not compile, but the int example does?

Community
  • 1
  • 1
rhughes
  • 9,257
  • 11
  • 59
  • 87
  • Probably because of the very warning you've mentioned. The compiler will probably compile this down to `if (false)`. Which is correct, `x` can never be `null`. – Simon Whitehead Jan 24 '13 at 03:40
  • learn how to use the `?` this will not compile `int? y = (int)null;` however at runtime this will compile `int? y = (int?)null;` do you understand what the `?` does ..? – MethodMan Jan 24 '13 at 03:44
  • also this won't compile `int? z = (int)(int?)null; Error Nullable type must have a value` however this will compile `int? z = (int?)(int?)null;` test it out.. good luck and happy coding – MethodMan Jan 24 '13 at 03:46
  • 1
    `int z = (int)(int?)null;` compiles. I understand `?` but my question is to do with `if (x == null)` – rhughes Jan 24 '13 at 03:50
  • I see no problem here, if (true == false), that compiles too. This because of operator overload resolution, There is an == operator that takes two `int?`(nullable). And since `int` is convertable to `int?` this will compile, however will always be false, basically it chooses the best operator overload, in this case it chose `int? == int?` due to the null on the right hand side. – sa_ddam213 Jan 24 '13 at 03:50
  • that compiles but will error because you need to assign both (int) as nullable does that make sense also there is a difference between `0 and null` – MethodMan Jan 24 '13 at 03:51
  • [Using Nullable Types](http://msdn.microsoft.com/en-US/library/2cf62fcy%28v=vs.80%29.aspx) here is some good reading Richard – MethodMan Jan 24 '13 at 03:59
  • This is OK: `int x = 5; int? y = null; if (x == y) ...`. Replacing `y` by a constant does not change any compatibility or overload rules. Since the compiler applies the same rules in both cases, both will compile. But it is of course not make much sense to compare `5 == null`, therefore the warning. – Olivier Jacot-Descombes Nov 17 '16 at 16:33

2 Answers2

7

When the comparison is made, the compiler tries to make it so both operands of the comparison have compatible types if possible.

It had an int value and a constant null value (with no particular type). The only compatible type between the two values is int? so they are coerced to int? and compared as int? == int?. Some int value as an int? is definitely non-null and null is definitely null. The compiler realizes that and since a non-null value is not equal to a definite null value, the warning is given.

Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
  • The compiler also optimizes this away because it is always false. It won't even load the `x` variable at all. – Simon Whitehead Jan 24 '13 at 03:53
  • Does it compile in versions of the .NET framework that does not support `Nullable`? – Guillaume Jan 24 '13 at 03:54
  • @Guillaume: I'm not sure to be honest, but I'd guess yes. I'd imagine they will be compared as `object` in that case (and will have the same warning). – Jeff Mercado Jan 24 '13 at 03:57
  • @Guillaume: Actually, based on Rich's update, it would appear it will fail. The compiler wouldn't coerce value types to `object` it would seem. – Jeff Mercado Jan 24 '13 at 04:01
  • 1
    @Guillaume: Eric Lippert's answer on the duplicate question explains it much clearer. This is only done because there is an `==` operator overload which compares two nullables of the same type. There generally wouldn't be one between a value type and a reference type so it will typically fail. – Jeff Mercado Jan 24 '13 at 05:25
  • @JeffMercado So I guess it won't compile in .NET 1.1... – Guillaume Jan 25 '13 at 02:29
1

actually compilation allow comparing 'int?' to 'int' not 'int' to null which make sense

e.g.

        int? nullableData = 5;
        int data = 10;
        data = (int)nullableData;// this make sense
        nullableData = data;// this make sense

        // you can assign null to int 
        nullableData = null;
        // same as above statment.
        nullableData = (int?)null;

        data = (int)(int?)null;
        // actually you are converting from 'int?' to 'int' 
        // which can be detected only at runtime if allowed or not

and that's what you are trying to do in int z = (int)(int?)null;

D J
  • 6,908
  • 13
  • 43
  • 75