Search code examples
c#nullablestring-interning

Can't intern Nullable DateTime


I'm trying to intern some object values that are passed kept in memory for long periods of time. Some of those objects are Nullable value types. I'm not able to properly intern Nullable values, I think there might be some sort of "helpful" autoboxing happening that I don't understand. Here's my unit test that should be passing (assuming Nullalbes behaved like objects) but isn't:

[Test]
public void InternNullableType()
{
    DateTime? one = new DateTime(2010, 2, 3, 4, 5, 6, DateTimeKind.Utc);
    DateTime? two = new DateTime(2010, 2, 3, 4, 5, 6, DateTimeKind.Utc);

    // should be equal, but not reference equal
    Assert.False(ReferenceEquals(one, two));
    Assert.True(one.Equals(two));

    // create an interning dictionary
    Dictionary<DateTime?, DateTime?> intern = new Dictionary<DateTime?, DateTime?>();
    intern[one] = one; // add 'one', this will be the value we hand out
    two = intern[two]; // intern the value of two

    // values should be equal, and reference qual
    Assert.True(one.Equals(two));     

    // this fails when it passes for objects       
    Assert.True(ReferenceEquals(one, two));
}

What's going on here?


Solution

  • Nullable types are structs, they are not objects. They are special structs that can be assigned null. So interning won't work as it does with strings because string is a reference type.

    When you retrieve the value of a nullable object, the boxed value is unboxed and new nullable instance is created with that value. That's why the ReferenceEquals returns false.

    From the docs:

    When a nullable type is boxed, the common language runtime automatically boxes the underlying value of the Nullable object, not the Nullable<T> object itself. That is, if the HasValue property is true, the contents of the Value property is boxed. When the underlying value of a nullable type is unboxed, the common language runtime creates a new Nullable<T> structure initialized to the underlying value.