Nullable<T> 的装箱/拆箱行为如何?可能的? [英] How is the boxing/unboxing behavior of Nullable&lt;T&gt; possible?

查看:18
本文介绍了Nullable<T> 的装箱/拆箱行为如何?可能的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天早些时候我突然想到了一些让我挠头的事情.

Something just occurred to me earlier today that has got me scratching my head.

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

Any variable of type Nullable<T> can be assigned to null. For instance:

int? i = null;

起初,如果不以某种方式定义从 objectNullable<T> 的隐式转换,我不知道这怎么可能:

At first I couldn't see how this would be possible without somehow defining an implicit conversion from object to Nullable<T>:

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

但是上面的操作符显然不存在,好像它存在一样,那么以下也必须是合法的,至少在编译时(它不是):

But the above operator clearly does not exist, as if it did then the following would also have to be legal, at least at compile-time (which it isn't):

int? i = new object();

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

Then I realized that perhaps the Nullable<T> type could define an implicit conversion to some arbitrary reference type that can never be instantiated, like this:

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 值,HasValue 属性是 false,然后该值将被装箱为 null:

However, this does not explain what occurred to me next: if the HasValue property is false for any Nullable<T> value, then that value will be boxed as null:

int? i = new int?();
object x = i; // Now x is null.

此外,如果 HasValuetrue该值将被装箱为 T 而不是一个T?:

Furthermore, if HasValue is true, then the value will be boxed as a T rather than a T?:

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

但是this似乎暗示了从Nullableobject的自定义隐式转换:

But this seems to imply that there is a custom implicit conversion from Nullable<T> to object:

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

这显然不是这种情况,因为 object 是所有类型的基类,并且用户定义的与基类型之间的隐式转换是非法的(它们应该是).

This is clearly not the case as object is a base class for all types, and user-defined implicit conversions to/from base types are illegal (as well they should be).

似乎 object x = i; 应该像任何其他值类型一样装箱 i,这样 x.GetType() 就会产生与 typeof(int?) 相同的结果(而不是抛出 NullReferenceException).

It seems that object x = i; should box i like any other value type, so that x.GetType() would yield the same result as typeof(int?) (rather than throw a NullReferenceException).

所以我仔细研究了一下,果然,结果证明这种行为特定于 Nullable 类型,在 C# 和 VB.NET 规范中专门定义,而不是可在任何用户定义的 struct (C#) 或 Structure (VB.NET) 中重现.

So I dug around a bit and, sure enough, it turns out this behavior is specific to the Nullable<T> type, specially defined in both the C# and VB.NET specifications, and not reproducible in any user-defined struct (C#) or Structure (VB.NET).

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

Here's why I'm still confused.

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

This particular boxing and unboxing behavior appears to be impossible to implement by hand. It only works because both C# and VB.NET give special treatment to the Nullable<T> type.

  1. 在没有给予 Nullable 这种特殊待遇的情况下,理论上是否可能存在一种不同的基于 CLI 的语言?那么 Nullable 类型不会因此在不同的语言中表现出不同的行为吗?

  1. Isn't it theoretically possible that a different CLI-based language could exist where Nullable<T> weren't given this special treatment? And wouldn't the Nullable<T> type therefore exhibit different behavior in different languages?

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

How do C# and VB.NET achieve this behavior? Is it supported by the CLR? (That is, does the CLR allow a type to somehow "override" the manner in which it is boxed, even though C# and VB.NET themselves prohibit it?)

是否可能(在 C# 或 VB.NET 中)将 Nullable 装箱为 object?

Is it even possible (in C# or VB.NET) to box a Nullable<T> as object?

推荐答案

有两件事正在发生:

1) 编译器不将null"视为 null reference 而是将其视为 null value ...它需要转换为的任何类型的 null 值.在 Nullable 的情况下,它只是 HasValue 字段/属性具有 False 的值.因此,如果您有一个 int? 类型的变量,那么该变量的值很可能为 null - 您只需要改变对 的理解null 表示一点点.

1) The compiler treats "null" not as a null reference but as a null value... the null value for whatever type it needs to convert to. In the case of a Nullable<T> it's just the value which has False for the HasValue field/property. So if you have a variable of type int?, it's quite possible for the value of that variable to be null - you just need to change your understanding of what null means a little bit.

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

2) Boxing nullable types gets special treatment by the CLR itself. This is relevant in your second example:

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

编译器会将任何可空类型值装箱到与不可空类型值不同的箱中.如果该值不为空,则结果将与将相同的值装箱为不可为空类型值的结果相同 - 因此,值为 5 的 int? 以与 int? 相同的方式装箱code>int 值为 5 - 可空性"丢失.然而,可空类型的空值被装箱到空引用,而不是创建一个对象.

the compiler will box any nullable type value differently to non-nullable type values. If the value isn't null, the result will be the same as boxing the same value as a non-nullable type value - so an int? with value 5 gets boxed in the same way as an int with value 5 - the "nullability" is lost. However, the null value of a nullable type is boxed to just the null reference, rather than creating an object at all.

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

This was introduced late in the CLR v2 cycle, at the request of the community.

这意味着没有装箱的可空值类型值"这样的东西.

It means there's no such thing as a "boxed nullable-value-type value".

这篇关于Nullable<T> 的装箱/拆箱行为如何?可能的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆