c# - Nullable<T> 的装箱/拆箱行为如何可能?

标签 c# .net vb.net nullable boxing

今天早些时候发生的一件事让我摸不着头脑。

Nullable<T> 类型的任何变量可以分配给null .例如:

int? i = null;

起初我看不出如果不以某种方式定义从 object 的隐式转换,这怎么可能至 Nullable<T> :

public static implicit operator Nullable<T>(object box);

但是上面的运算符显然不存在,就好像它存在那么下面的运算符也必须是合法的,至少在编译时(它不是):

int? i = new object();

然后我意识到也许 Nullable<T> type 可以定义到一些永远无法实例化的任意引用类型的隐式转换,如下所示:

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.

此外,如果HasValuetrue , 然后 该值将装箱为 T而不是 T? :

int? i = 5;
object x = i; // Now x is a boxed int, NOT a boxed Nullable<int>.

但是似乎暗示有一个来自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 规范中专门定义,并且在任何用户定义中不可重现 struct (C#) 或 Structure (VB.NET)。

这就是为什么我仍然感到困惑。

这种特殊的装箱和拆箱行为似乎无法手动实现。它之所以有效,是因为 C# 和 VB.NET 都对 Nullable<T> 进行了特殊处理。类型。

  1. Nullable<T> 的地方,理论上是否可能存在一种不同的基于 CLI 的语言?没有得到这种特殊待遇?而且不会 Nullable<T> type 因此在不同的语言中表现出不同的行为

  2. C# 和 VB.NET 如何实现这种行为? CLR 支持吗? (也就是说,CLR 是否允许类型以某种方式“覆盖”它的装箱方式,即使 C# 和 VB.NET 本身禁止它?)

  3. 可能(在 C# 或 VB.NET 中)将 Nullable<T> 装箱吗?作为object ?

最佳答案

有两件事正在发生:

1) 编译器不将“null”视为空引用,而是将其视为空...它需要转换成的任何类型的空值。在 Nullable<T> 的情况下这只是 HasValue 的 False 值领域/属性(property)。所以如果你有一个 int? 类型的变量, 该变量的值很可能是 null - 你只需要改变你对什么的理解null有点意思。

2) 装箱可为空的类型得到 CLR 本身的特殊处理。这与您的第二个示例相关:

    int? i = new int?();
    object x = i;

编译器会将任何可空类型值与非可空类型值不同地装箱。如果该值不为空,则结果将与将相同值装箱为不可空类型值相同 - 所以 int?值为 5 的装箱方式与 int 相同值为 5 - “可空性”丢失。但是,可空类型的空值仅装箱为空引用,而不是创建一个对象。

应社区的要求,这是在 CLR v2 周期的后期引入的。

这意味着没有“装箱的可空值类型值”这样的东西。

关于c# - Nullable<T> 的装箱/拆箱行为如何可能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3775582/

相关文章:

c# - 了解 MassTransit 中的 "Finalize"

c# - 实现 IList 接口(interface)

c# - 如何使用 .Net(在 Windows Phone 上)阅读公共(public)推特提要

windows - 如何禁用 Windows 注册表中的剪切、复制、粘贴、重命名等操作?

mysql - 如何处理并发(多个用户编辑相同数据)- VB.NET 特色 MySQL

vb.net - 在 VB6 代码中处理 VB.NET 事件

c# - 'as dynamic[]' 和 ToArray() 之间的区别

C#4 : Dynamic and Nullable<>

.net - 非托管 dll 调用使 dotnet 应用程序崩溃?

asp.net - 如何将消息记录到 Windows Azure 存储?