72

selectedItem has two fields:

  • int? _cost
  • string _serialNumber

In this example, _cost and _serialNumber of selectedItem are BOTH null. I am reading through the fields of selectedItem via their properties, and filling in textboxes with their values, when...

TextBox1.Text = selectedItem.Cost.ToString(); //no error
TextBox2.Text = selectedItem.SerialNumber.ToString(); //error

I understand that SerialNumber.ToString() is redundant (because it is already a string), but I don't understand why this causes this exception:

Nullable object must have a value.

  • int? _cost is nullable, and does not have a value, yet it does not give me the exception.
  • string _serialNumber is nullable, and does not have a value, yet it does give me the exception.

This question touches on it, the guy is essentially asking the same thing, but there is no designated answer, and it also doesn't explain why a nullable int? For example, can I use .ToString() on a nullable int but not on a null string?

Community
  • 1
  • 1
CptSupermrkt
  • 6,844
  • 12
  • 56
  • 87
  • The question you linked to is not the same at all. That question is about how `MessageBox.Show` and `String.Concat` work with `null` strings. – Mark Byers Jul 12 '12 at 10:28
  • 9
    Note that you're using the word "nullable" to mean two totally different things. `int?` is a value type, which is called `Nullable`, that has special handling for null values; `string` is a reference type, (though a somewhat odd one) which can *actually have* a value of `null`. An `int?` always has a value, it just has a special way of saying "I'm acting like `null` right now." – Michael Edenfield Jul 12 '12 at 16:45

8 Answers8

91

Because string type's null really points to nothing, there isn't any object in memory.
But int? type(nullable) even with value set to null still points to some object.
If you read Jeffrey Richter's "CLR via C#" you'll find out that nullable type are just facade classes for common types with some incapsulated logics in order to make work with DB null more convenient.

Check msdn to learn about nullable types.

Johnny_D
  • 4,592
  • 3
  • 33
  • 63
  • 8
    So basically because it's not actually null, it's just pretending to be? – The Oddler Jul 12 '12 at 11:56
  • 4
    Yes, basically it's a structure wrapped around an int field and boolean sign indicating whether this structure was set to int value, or still unitialized, which mean null. In [this](http://stackoverflow.com/questions/2503811/how-are-nullable-types-implemented-under-the-hood-in-net) topic Mark Gravell pasted implementation on `Nullable` type. – Johnny_D Jul 12 '12 at 12:17
  • 1
    `int?` or `Int32?`. Not `Int?` – turbanoff Jul 18 '12 at 07:12
  • 4
    This is all correct, but also note that `selectedItem.Cost.GetType()` *will* throw if `Cost` is null of type `int?`. The difference is that `ToString` is a virtual method which is overridden by `Nullable` and so can be called on the `int?` directly. On the other hand `GetType` is a non-virtual method declared on a base class of `Nullable` (on `object` in fact). Therefore the runtime will have to convert the `Nullable<>` to that class type before it can call `GetType`, and that is what is called **boxing**, but `Nullable<>` has special boxing rules, so a null reference is produced. – Jeppe Stig Nielsen Aug 25 '13 at 15:06
34

A Nullable<int> is a struct and can't really be null. So a method call on a "null" struct still works.

There is some "compiler magic" that makes _cost == null a valid expression.

Hans Kesting
  • 38,117
  • 9
  • 79
  • 111
  • 5
    It's compiler magic. Adding an implicit conversion from `null` to `Nullable` using ordinary C# code (i.e. operator overloading) would require that you be able to infer a type from the expression "`null`", which you can't, as it doesn't have one. The compiler essentially turns `Nullable foo = null` into `Nullable foo = default(Nullable)` and `foo == null` into `!foo.HasValue`. – Adam Robinson Jul 12 '12 at 21:30
16

int? is not actually an object in its own but it's a Nullable<int> object.

So when you declare int? _Cost, you are actually declaring Nullable<int> _Cost and the property of _Cost.Value is undefined not the _Cost object itself.

It is actually a syntactic sugar to use non nullable types like int, bool or decimal easily.

According to MSDN:

The syntax T? is shorthand for System.Nullable<T>, where T is a value type. The two forms are interchangeable.

shA.t
  • 16,580
  • 5
  • 54
  • 111
Asif Mushtaq
  • 13,010
  • 3
  • 33
  • 42
4

The Nullable is actually a struct exposing two properties: HasValue and Value. If you do this you will get your error:

int? i = null;
i.Value.ToString()

In order to check whether or not your int? has a value you can access i.HasValue

  • 2
    Not _completely_ true. That code will not throw a `NullReferenceException`, but an `InvalidOperationException`. See [Nullable(T).Value](http://msdn.microsoft.com/en-us/library/ydkbatt6.aspx). – comecme Jul 12 '12 at 18:52
4

A string is a reference type, but a nullable int is a value type. Here is a Good discussion of the differences http://www.albahari.com/valuevsreftypes.aspx.

3

The reason is simple. int? or Nullable<int> is a struct or a value type, it can never be null.

So what happens when we do:

int? _cost = null;

_cost will have two fields Value and HasValue, when we assign null to _cost its HasValue flag will be set to false and the Value field would be assigned default(T) in case of int? it would 0.

Now when we call ToString on _cost, Nullable<T> has an override definition of ToString, which if we look at Microsoft's provided Source Reference is implemented like:

public override string ToString() {
    return HasValue ? value.ToString() : "";
}

Thus it returns an empty string, since _cost is assigned null.

Now comes the case of string _serialNumber. Being string it is a reference type and it can purely hold null. If it is holding null then calling ToString on it would produce the Null Reference Exception as expected.

You may see: Value Types and Reference Types - MSDN

Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90
Habib
  • 219,104
  • 29
  • 407
  • 436
1

what i think the reason is, when the compiler encounters a primitive data type it wraps it, to its corresponding object. The toString() method call is just an indirect call(wrapping and then calling the method) here and the exception is handled there. While in the case of String, we are directly calling the method. When pointing to a null, the method throws the exception.

Sashi Kant
  • 13,277
  • 9
  • 44
  • 71
0
TextBox2.Text = selectedItem.SerialNumber.ToString(); //error

yiels error because it's calling function ToString() which is member of System.String. This function returns this instance of System.String; no actual conversion is performed. Also, String is a reference type. A reference type contains a pointer to another memory location that holds the data.

TextBox1.Text = selectedItem.Cost.ToString(); //no error

yields no error because it's calling to function ToString() which is a member of System.Integer. This function converts the numeric value of this instance to its equivalent string representation. Also, Integer is a value type. A data type is a value type if it holds the data within its own memory allocation.

The same function name ToString() but performs different task.

String.ToString Method

Int32.ToString Method

Value types and reference types

Tola
  • 2,401
  • 10
  • 36
  • 60