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?
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 theHasValue
property is true, the contents of theValue
property is boxed. When the underlying value of a nullable type is unboxed, the common language runtime creates a newNullable<T>
structure initialized to the underlying value.