如何可以为空1所述的装箱/拆箱的行为; T>可能? [英] How is the boxing/unboxing behavior of Nullable<T> possible?

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

问题描述

东西在今天早些时候已经让我抓我的头刚刚发生在我身上。

类型的任何变量可空< T> 可分配给。例如:

 诠释? I = NULL;
 

起初我看不出如何做到这一点是可能的,而不以某种方式定义的隐式转换,从对象可空< T>

 公共静态隐含的运营商可空< T>(对象框);
 

但上面的操作员显然不存在,就好像它没有那么下面也必须是合法的,至少在编译时间(它是不是):

 诠释? I =新的对象();
 

后来我才意识到,也许可空< T> 键入可以定义的隐式转换到一些任意的引用类型是不能被实例化,像这样的:

 公共抽象类DummyBox
{
    私人DummyBox()
    {}
}

公共结构可空< T>其中T:结构
{
    公共静态隐含的运营商可空< T>(DummyBox盒)
    {
        如果(盒== NULL)
        {
            回到新的可空< T>();
        }

        //这不应该是可能的,因为一个DummyBox不能被实例化。
        抛出新InvalidCastException的();
    }
}
 

不过,这并不能说明什么发生,我旁边:如果 hasVa​​lue的属性任何可空< T> 值,则该值将被装箱为

 诠释? I =新INT()?;
对象X = 1; //现在x为空。
 

此外,如果 hasVa​​lue的然后的值将被装箱为一个 T ,而不是 T

 诠释? I = 5;
对象X = 1; //现在x是装箱的int,而不是一个盒装的可空< INT取代。
 

不过的这个的似乎暗示,有一个从可空&LT的自定义隐式转换; T> 对象

 公共静态隐式操作符对象(可空< T>值);
 

这显然并非如此,因为对象是所有类型的基类,以及用户自定义隐式转换为/从基本类型是非法的(当然,他们应该定)。

看来,对象X = 1; 应盒像任何其他值类型,使 x.GetType()会产生相同的结果为 typeof运算(INT?)(而不是抛出一个的NullReferenceException )。

所以,我周围挖了一下,果然,事实证明这种行为是特定于可空< T> 键入,同时在C#和VB特殊定义.NET的规格,并在用户定义的任何结构(C#)不可再生或结构(VB.NET)。

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

这个特殊的装箱和拆箱的行为似乎是不可能用手工来实现。它只能是因为C#和VB.NET给予特殊治疗,在可空< T> 键入

  1. 是不是理论上可能是不同的基于CLI的语言可能存在其中可空< T> 并没有给予这个特殊的待遇?并且不会对可空< T> 键入因此表现出的不同的行为的不同语言

  2. 如何C#和VB.NET的实现的这种行为?是它支持CLR的? (也就是说,它的CLR允许类型以某种方式替代,即它是盒装的方式,尽管C#和VB.NET自己禁止了吗​​?)

  3. 它甚至的可能的(在C#或VB.NET)框一个可空< T> 对象

解决方案

有两件事情怎么回事:

1),编译器将空不是空的引用的,但作为一个空的的...空值的任何类型需要转换为。在可空1所述的情况下,T> 这只是其中有假的 hasVa​​lue的字段/属性的值。 ?所以,如果你有键入 INT 的变量,它很可能该变量的值设置为 - 你只需要改变你的什么表示一点点的了解。

2)拳击空类型得到特殊待遇由CLR本身。这是你的第二个例子相关的:

 诠释? I =新INT()?;
    对象X = 1;
 

编译器会有所不同框中的任何可空类型值,以非可空类型的值。如果该值不为空,则结果会是一样的拳击相同的值作为非可空类型值 - 这样的 INT 值为5得到盒装以同样的方式为 INT 值为5 - 的空性的丧失。然而,可空类型的空值是盒装,只是空引用,而不是创建一个对象都没有。

这被引入后期的CLR V2周期,在​​社区的要求。

这意味着有没有这样的东西作为一个盒装可空值类型的价值。

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

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

int? i = null;

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();

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();
    }
}

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.

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>.

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);

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).

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).

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.

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. 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?

  2. 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?)

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

解决方案

There are two things going on:

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) Boxing nullable types gets special treatment by the CLR itself. This is relevant in your second example:

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

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.

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".

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

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