8
int? x = null;
x = x + 1;  // Works, but x remains null

I would expect the compiler to attempt to cast x as an int, but apparently it does not.

Edit by 280Z28: Changed NullReferenceException to InvalidOperationException, which is what Nullable<T>.Value throws when HasValue is false.

newdayrising
  • 3,762
  • 4
  • 27
  • 31

7 Answers7

10

This is per the specification for lifted binary operators. From §7.2.7:

For the binary operators

+ - * / % & | ^ << >>

a lifted form of an operator exists if the operand and result types are all non-nullable value types. The lifted form is constructed by adding a single ? modifier to each operand and result type. The lifted operator produces a null value if one or both operands are null (an exception being the & and | operators of the bool? type, as described in §7.10.3). Otherwise, the lifted operator unwraps the operands, applies the underlying operator, and wraps the result.

The reasoning is this: you are to think of null for a nullable type as meaning "I do not know what the value is." What is the result of "I don't know" plus one? "I don't know." Thus, the result should be null.

Community
  • 1
  • 1
jason
  • 236,483
  • 35
  • 423
  • 525
  • Your logic is well phrased, but it really should throw an exception. Think of + as just syntactically cooler way of running number.Plus(2). It should definitely throw an exception if number is null or it can easily cause unexpected behaviour. – Niels Brinch Aug 28 '12 at 11:44
  • Even worse, if you have a number and ADD null to it, it will become null. – Niels Brinch Aug 28 '12 at 11:52
5

Nullables are never actually null references. They are always object references. Their internal classes override the == and = operators. If they are being compared to null, they'll return the value of the HasValue property.

rusty
  • 2,771
  • 1
  • 24
  • 23
  • 1
    The first sentence is correct. The middle two sentences are incorrect. Nullables are *never* object references. The Nullable struct does *not* override the equality operator. There is no such thing as overriding the assignment operator. The last sentence is correct. – Eric Lippert Jan 28 '10 at 23:41
  • You're right -- not the assignment operator, but the implicit conversion from an int. They're definitely different operators but in the end the effect is the same. Thanks for pointing that out. – rusty Jan 29 '10 at 14:05
2

Why would you expect the compiler to cast it as int when you've declared it as Nullable? The compiler is doing what you've told it to do and null +1 = null.

You'll have to cast explicitly or check x.HasValue before attempting to add an int.

Barracoder
  • 3,696
  • 2
  • 28
  • 31
2

The reason for this is that the compiler creates a 'lifted' operator for nullable types - in this case it is something like:

public static int? operator +(int? a, int? b)
{
    return (a == null || b == null) ? (int?)null : a.Value + b.Value
}

I think if you try to assign the result to a non-nullable value, the compiler will be forced to use the non-nullable overload and convert x to an int.

e.g. int i = x + 1;  //throws runtime exception
Lee
  • 142,018
  • 20
  • 234
  • 287
  • actually int i = x + 1 is an error. int i = (int)(x + 1) will throw an exception if x has no value. – Dolphin Jan 28 '10 at 17:25
0

Unfortunately it doesn't. The X in x = X + 1 is null as in the first line so you're adding 1 to null, which equals null.

As it's a nullable int, you can use x.HasValue to check if it has a value, and then x.Value to get the actual int value out

Paul
  • 9,409
  • 13
  • 64
  • 113
0

Regardless of whether x is actually never null, that's not even the point.

The point is, when have you ever seen a NullReferenceException when trying to perform an addition?

The following example doesn't throw a NullReferenceException either and is perfectly valid.

string hello = null;
string world = "world";
string hw = hello+world;

You would only get a NullReferenceException if you try to access a member on an object that is null.

Wim
  • 11,998
  • 1
  • 34
  • 57
-1

int? can never be null because it is a struct. Structs live on the stack and the stack does not handle null well.

See What is a NullPointerException, and how do I fix it?

Also, the nullable types have 2 very useful properties : HasValue, Value

This code:

        if (x != null)
        {
            return (int) x;
        }

Should be refactored to this:

        if (x.HasValue)
        {
            return x.Value;
        }
Community
  • 1
  • 1
fremis
  • 584
  • 4
  • 4
  • This is completely incorrect. First, value types do not "live on the stack". Value types live wherever they live, on either the stack or the heap, as the memory manager sees fit. Second, it is perfectly legal to have a null reference on the stack. "string s = null;", there's a null reference on the stack, no problem. – Eric Lippert Jan 28 '10 at 23:46
  • 1
    I appreciate the correction. When I first started in .NET I remember doing this: DateTime x = null; and getting this error "The compiler cannot assign null to a value type; null can only be assigned to a reference type. struct is a value type." I misunderstood the message. The error is talking about the limitations of the null-literal and not the value type. Thanks for the well deserved slap in the head. – fremis Jan 29 '10 at 04:24