15

Have you ever tried to use the Convert.ChangeType() method to convert a value to a Nullable<T> type? Awkwardly, it will throw an InvalidCastException saying "Null object cannot be converted to a value type".

Try running this on your immediate window: ?System.Convert.ChangeType(null, typeof(int?))

For some obscure reason, Nullables are considered value types. For example, typeof(int?).IsValueType returns true.

For me, since Nullable<T> accept null, it's a class type, not a value type. Does anyone know why it would implemented differently?

jpbochi
  • 4,366
  • 3
  • 34
  • 43

4 Answers4

32

System.Nullable<T> is technically a structure, so it's a value type (the null value for a Nullable<T> is not exactly the same thing as a null reference. It's a boolean flag that denotes the lack of a value.) However, it's treated specially by the runtime and this makes it an awkward value type. First, it doesn't satisfy where T : struct type constraint (it doesn't satisfy where T : class either, for what it's worth). Second, it exhibits an interesting boxing behavior. Boxing a Nullable<T> will result in:

  • A null reference, if the value is null.
  • A boxed value of the underlying type if it actually contains a value. That is, in the statements:

    int? x = 2;
    object y = x;
    

    y is not a boxed Nullable<int>. It's simply a boxed int. You can unbox any boxed value of type T to Nullable<T> (and T, of course). Casting a null reference to Nullable<T> results in a null value (as you might expect).

This special treatment by the runtime makes nullable types work more similar to the way null works in reference types.

Randy Levy
  • 22,566
  • 4
  • 68
  • 94
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • 3
    The strange boxing behavior takes a while to understand - but I'm glad it's the way it is; otherwise much of the value of `Nullable` (which comes from value passing transparency) would be lost. – LBushkin Jan 08 '10 at 22:03
  • 1
    Actually, the boxing behavior was a change that happened late in the development cycle of .NET 2.0. In early betas, `Nullable` was a simple structure. In practice when you actually use nullable types to store nonexistent values, I too feel this behavior is more natural. – Mehrdad Afshari Jan 08 '10 at 22:07
  • Also, `Convert.ChangeType` considers `Nullable<>` a ValueType as far as null values go, and therefore cannot change `null` to a `Nullable<>` type, which is absolutely ridiculous, considering there's an implicit conversion from `null` to `Nullable<>`. Maybe they were afraid of incurring the overhead of checking `bool IsNullable(Type type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)`? – Triynko Aug 24 '18 at 17:24
12

Nullable<T> is a value type (it's a struct, see in the MSDN documentation), but there is an implicit conversion from null to a Nullable<T> without a value (x.HasValue == false). There is also an implicit conversion from values of type T to values of type Nullable<T>.

Additionally all operators are lifted from the regular types to work directly with nullable types.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
2

I just saw this question in the "related questions" list at Why Nullable<T> is a struct? and I think my answer there applies here too. The whole point of Nullable<T> is to act like a value type in every regard except for the ability to take a null value.

The null of a null reference can be looked at in two ways. One is that it isn't referencing anything, another is that it has no meaningful value. These things are pretty much two different ways of saying the same thing, but they have different uses.

Nullable<T> gives us the ability to say "this has no meaningful value" and to that extent it can have the same semantics as a null reference, but it is not like a reference in any other way. When null it's nullity is purely that "no meaningful value" null - not "doesn't refer to anything" and when not null it is holding a value, not referring to it.

(Aaronaught argues that this means a Nullable can't really contain null, while I disagree because at the level at which it uses it can have a semantic null, his point is worth considering in that even when "null" a Nullable is different to a reference - really our disagreement is a matter of which level of abstraction we choose to use).

Community
  • 1
  • 1
Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
1

Nullable<T> is implemented as a struct and structs are value types.

Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • 2
    But no struct can receive a `null` value. I believe that Nullables are different enough from structs to not be considered structs. – jpbochi Jan 08 '10 at 22:00
  • 2
    `Nullable` can't receive a `null` value either, it just has an implicit conversion to and from `null`. You could implement this on any custom `struct`, if you so desired. – Aaronaught Jan 08 '10 at 22:04
  • 5
    @Aaronaught: you can do something *similar* with a custom struct, but a lot of the behavior of nullable types cannot be mimicked through code. Nullable values are not just a library solution. They get special support from the compiler (and the CLR too, I think). – R. Martinho Fernandes Jan 08 '10 at 22:08