【发布时间】:2011-04-16 02:11:16
【问题描述】:
今天早些时候我发生了一件让我摸不着头脑的事情。
Nullable<T> 类型的任何变量都可以分配给null。例如:
int? i = null;
起初,如果不以某种方式定义从 object 到 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();
}
}
但是,这并不能解释我接下来发生的事情:如果任何 Nullable<T> 值的 HasValue 属性是 false,那么该值将被装箱为 null:
int? i = new int?();
object x = i; // Now x is null.
此外,如果HasValue 是true,那么该值将被装箱为T 而不是T?:
int? i = 5;
object x = i; // Now x is a boxed int, NOT a boxed Nullable<int>.
但是 this 似乎暗示了从 Nullable<T> 到 object 的自定义隐式转换:
public static implicit operator object(Nullable<T> value);
显然情况并非如此,因为object 是所有类型的基类,并且用户定义的与基类型之间的隐式转换是非法的(也应该如此)。
似乎object x = i; 应该像任何其他值类型一样将i 装箱,这样x.GetType() 将产生与typeof(int?) 相同的结果(而不是抛出NullReferenceException)。
所以我挖了一下,果然,这种行为是特定于 Nullable<T> 类型的,在 C# 和 VB.NET 规范中都特别定义,并且在任何用户定义的 @987654352 中都无法重现@ (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 中)将
Nullable<T>装箱为object?
【问题讨论】:
-
实现行为的是 JIT 编译器。更多信息:stackoverflow.com/questions/1583050/…
-
我意识到我迟到了 7 年。但是,我想建议任何像我一样好奇的人也阅读参考资料以获得更多洞察力。 referencesource.microsoft.com/#mscorlib/system/…
标签: c# .net vb.net nullable boxing