无法实习可为空的日期时间
Can't intern Nullable DateTime
我正在尝试实习一些长期保存在内存中的对象值。其中一些对象是 Nullable 值类型。我无法正确地实习 Nullable 值,我认为可能会发生某种我不理解的 "helpful" 自动装箱。这是我应该通过的单元测试(假设 Nullalbes 表现得像对象)但不是:
[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));
}
这是怎么回事?
one
和 two
对象是不同的对象。
Nullable
值类型仍然是值类型。
ReferenceEquals
方法比较它们的指针值,会是false
因为它们的指针值不同
Nullable<>
是值类型。
调用 ReferenceEquals
是没有意义的,它会将两个值装箱到不同的对象中,因此总是 return false。
你想用这个 "interning" 达到什么目的?
DateTime?
仍然是一个不可变的值类型。把它想象成一个整数。
int a = 1;
int b = 1;
//a == b <--- true
//ReferenceEquals(a, b) <--- false
int c = b;
//c == b <--- true
//ReferenceEquals(c, b) <---- false
所以基本上你的 two = intern[two];
不是将 one
的地址存储到 two
而是创建一个新对象并从 one
[=17 复制值=]
DateTime? one = new DateTime(2010, 2, 3, 4, 5, 6, DateTimeKind.Utc);
Dictionary<DateTime?, DateTime?> intern = new Dictionary<DateTime?, DateTime?>();
intern[one] = one;
Console.WriteLine(ReferenceEquals(intern[one], intern[one])); <---false
Console.WriteLine(ReferenceEquals(one, intern[one])); <---false
可为 Null 的类型是结构,而不是对象。它们是可以分配为空的特殊结构。所以实习不会像字符串那样工作,因为 string
是引用类型。
当您检索可为 null 的对象的值时,装箱的值将被取消装箱,并使用该值创建新的可为 null 的实例。这就是为什么 ReferenceEquals
returns false
.
来自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.
我正在尝试实习一些长期保存在内存中的对象值。其中一些对象是 Nullable 值类型。我无法正确地实习 Nullable 值,我认为可能会发生某种我不理解的 "helpful" 自动装箱。这是我应该通过的单元测试(假设 Nullalbes 表现得像对象)但不是:
[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));
}
这是怎么回事?
one
和 two
对象是不同的对象。
Nullable
值类型仍然是值类型。
ReferenceEquals
方法比较它们的指针值,会是false
因为它们的指针值不同
Nullable<>
是值类型。
调用 ReferenceEquals
是没有意义的,它会将两个值装箱到不同的对象中,因此总是 return false。
你想用这个 "interning" 达到什么目的?
DateTime?
仍然是一个不可变的值类型。把它想象成一个整数。
int a = 1;
int b = 1;
//a == b <--- true
//ReferenceEquals(a, b) <--- false
int c = b;
//c == b <--- true
//ReferenceEquals(c, b) <---- false
所以基本上你的 two = intern[two];
不是将 one
的地址存储到 two
而是创建一个新对象并从 one
[=17 复制值=]
DateTime? one = new DateTime(2010, 2, 3, 4, 5, 6, DateTimeKind.Utc);
Dictionary<DateTime?, DateTime?> intern = new Dictionary<DateTime?, DateTime?>();
intern[one] = one;
Console.WriteLine(ReferenceEquals(intern[one], intern[one])); <---false
Console.WriteLine(ReferenceEquals(one, intern[one])); <---false
可为 Null 的类型是结构,而不是对象。它们是可以分配为空的特殊结构。所以实习不会像字符串那样工作,因为 string
是引用类型。
当您检索可为 null 的对象的值时,装箱的值将被取消装箱,并使用该值创建新的可为 null 的实例。这就是为什么 ReferenceEquals
returns false
.
来自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.