13

I'm curious to know how the Nullable type works behind the scenes. Is it creating a new object(objects can be assigned null) with a possible value of null?

In the example we use a Nullable<int>, is their some kind of implicit conversion from an object to an int and vice versa when you assign it a null value?

Also I know how this can be created manually, is there a benfit from using the Nullable type as opposed to creating it ourself?

Edward
  • 7,346
  • 8
  • 62
  • 123
  • @Rfvgyhn I don't really see how this is a duplicate. They wanted to know the difference between an int and a nullable. This is not what I asked. – Edward Apr 09 '11 at 04:09
  • @Frank how about instead of trying to close my question you post an answer to help me and the community. Obviously there are answers here that have not been mentioned or explained in the question your refering to. Also for the second time they do not ask what I asked for. – Edward Apr 09 '11 at 05:38

4 Answers4

13

The nullable type is a struct consisting of two fields: a bool and a T. When the value is null, the bool is false and the T has the default value. When the value is not null, the bool is true.

There are two main benefits to using Nullable as compared to implementing the functionality yourself. There's the language support, as described in more detail in ChaosPandion's answer, and there's the fact that boxing (converting to an object) will automatically remove the nullable "wrapper", leaving either a null reference or the plain T object.z

Random832
  • 37,415
  • 3
  • 44
  • 63
  • +1 for the great explanation. Do you have a reference for this where I can look into it in more detail? – Edward Apr 09 '11 at 04:12
  • 3
    On what aspect specifically? http://msdn.microsoft.com/en-us/library/ms228597.aspx explains the boxing thing. – Random832 Apr 09 '11 at 04:27
  • +1 Good answer, it was interesting to find out what Nullable consists of under the hood. – Ivan Golović Aug 03 '12 at 08:11
  • _**"When the value is null, the bool is false and the T has the default value."**_ What is the default value? Because when I use the following code `bool? x = null; if(x.Value) { }` I get InvalidOperationException. If the default value is assigned then why I'm getting an error? why not it returns me the default value. – Sharad Gaur May 23 '20 at 07:12
  • 1
    _**If the HasValue property is false, the value of the object is undefined**_ This is what I found in definition on Microsoft documentation [Link](https://learn.microsoft.com/en-us/dotnet/api/system.nullable-1?view=netframework-2.0#fundamental-properties) – Sharad Gaur May 24 '20 at 07:55
11

Here is the (tidied up) code from running .Net Reflector against Nullable...

[Serializable, StructLayout(LayoutKind.Sequential), TypeDependency("System.Collections.Generic.NullableComparer`1"), TypeDependency("System.Collections.Generic.NullableEqualityComparer`1")]
public struct Nullable<T> where T: struct
{

private bool hasValue;
internal T value;

public Nullable(T value)
{
    this.value = value;
    this.hasValue = true;
}

public bool HasValue
{
    get
    {
        return this.hasValue;
    }
}

public T Value
{
    get
    {
        if (!this.HasValue)
        {
            ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NoValue);
        }
        return this.value;
    }
}

public T GetValueOrDefault()
{
    return this.value;
}

public T GetValueOrDefault(T defaultValue)
{
    if (!this.HasValue)
    {
        return defaultValue;
    }
    return this.value;
}

public override bool Equals(object other)
{
    if (!this.HasValue)
    {
        return (other == null);
    }
    if (other == null)
    {
        return false;
    }
    return this.value.Equals(other);
}

public override int GetHashCode()
{
    if (!this.HasValue)
    {
        return 0;
    }
    return this.value.GetHashCode();
}

public override string ToString()
{
    if (!this.HasValue)
    {
        return "";
    }
    return this.value.ToString();
}

public static implicit operator Nullable<T>(T value)
{
    return new Nullable<T>(value);
}

public static explicit operator T(Nullable<T> value)
{
    return value.Value;
}
}
BlueRaja - Danny Pflughoeft
  • 84,206
  • 33
  • 197
  • 283
barrylloyd
  • 1,599
  • 1
  • 11
  • 18
10

It's actually quite simple. The compiler gives you a hand with the syntax.

// this
int? x = null;
// Transformed to this
int? x = new Nullable<int>()

// this
if (x == null) return;
// Transformed to this
if (!x.HasValue) return;

// this
if (x == 2) return;
// Transformed to this
if (x.GetValueOrDefault() == 2 && x.HasValue) return;
ChaosPandion
  • 77,506
  • 18
  • 119
  • 157
  • Could you verify (in reflector) that this is true? That last line, at the very least, should not be necessary, due to the `implicit operator Nullable` (see [@barrylloyd's answer](http://stackoverflow.com/questions/5602773/how-does-a-nullablet-type-work-behind-the-scenes/5602820#5602820)) – BlueRaja - Danny Pflughoeft Apr 09 '11 at 04:16
  • I ran this in linqpad and confirmed that the last line contains calls to the two properties. It's to do with how the == itself is implemented, even with another nullable. `if (x == y)` becomes `if(x.GetValueOrDefault() == y.GetValueOrDefault() && x.HasValue == y.HasValue)`. – Random832 Apr 09 '11 at 04:31
  • @BlueRaja - Danny Pflughoeft - That is what happens. – ChaosPandion Apr 09 '11 at 04:34
1

Nullable<T> is implemented as a struct that overrides Equals() to behave as null if HasValue is false. There is an implicit conversion from T to T?, and an explicit conversion in the other direction which throws if !HasValue.

dahlbyk
  • 75,175
  • 8
  • 100
  • 122