今天早些时候我发生了一件让我摸不着头脑的事情。
任何类型的变量Nullable<T>
都可以分配给null
. 例如:
int? i = null;
起初,如果不以某种方式定义从object
to的隐式转换,我看不到这怎么可能Nullable<T>
:
public static implicit operator Nullable<T>(object box);
但是上面的运算符显然不存在,就好像它确实存在那么以下也必须是合法的,至少在编译时(它不是):
int? i = new object();
然后我意识到,也许该Nullable<T>
类型可以定义隐式转换为一些永远无法实例化的任意引用类型,如下所示:
public abstract class DummyBox
{
private DummyBox()
{ }
}
public struct Nullable<T> where T : struct
{
public static implicit operator Nullable<T>(DummyBox box)
{
if (box == null)
{
return new Nullable<T>();
}
// This should never be possible, as a DummyBox cannot be instantiated.
throw new InvalidCastException();
}
}
但是,这并不能解释我接下来发生的事情:如果该HasValue
属性false
适用于任何Nullable<T>
值,则该值将被装箱为null
:
int? i = new int?();
object x = i; // Now x is null.
此外,如果HasValue
is true
,则该值将被装箱为 aT
而不是 a T?
:
int? i = 5;
object x = i; // Now x is a boxed int, NOT a boxed Nullable<int>.
但这似乎意味着存在从 to 的自定义隐式Nullable<T>
转换object
:
public static implicit operator object(Nullable<T> value);
这显然不是object
所有类型的基类,用户定义的与基类型之间的隐式转换是非法的(它们也应该如此)。
似乎object x = i;
应该像任何其他值类型一样装箱i
,这样x.GetType()
会产生与typeof(int?)
(而不是 throw a NullReferenceException
)相同的结果。
所以我挖了一下,果然,事实证明这种行为是特定于Nullable<T>
类型的,在 C# 和 VB.NET 规范中特别定义,并且在任何用户定义的struct
(C#) 或Structure
(VB.NET ) 中都不可重现)。
这就是为什么我仍然感到困惑。
这种特殊的装箱和拆箱行为似乎无法手动实现。它之所以有效,是因为 C# 和 VB.NET 都对Nullable<T>
类型进行了特殊处理。
Nullable<T>
在没有给予这种特殊处理的情况下,理论上是否可能存在不同的基于 CLI 的语言?Nullable<T>
并且该类型不会因此在不同的语言中表现出不同的行为吗?C# 和 VB.NET 如何实现这种行为?CLR 支持吗?(也就是说,CLR 是否允许一个类型以某种方式“覆盖”它的装箱方式,即使 C# 和 VB.NET 本身禁止它?)
甚至有可能(在 C# 或 VB.NET 中)将 a 装箱
Nullable<T>
吗object
?