C# - 装箱/拆箱/类型转换的问题。我不明白

时间:2012-01-07 17:12:26

标签: c# c#-4.0 casting boxing unboxing

我很难理解这一点。请考虑以下示例:

protected void Page_Load(object sender, EventArgs e)
{
    // No surprise that this works
    Int16 firstTest = Convert.ToInt16(0);
    int firstTest2 = (int)firstTest;

    // This also works
    object secondTest = 0;
    int secondTest2 = (int)secondTest;

    // But this fails!
    object thirdTest = Convert.ToInt16(0);
    int thirdtest2 = (int)thirdTest;  // It blows up on this line.
}

我在运行时获得的具体错误是Specified cast is not valid.如果我在Visual Studio中使用QuickWatch (int)thirdTest,则会得到Cannot unbox 'thirdTest' as a 'int'的值。

这到底是怎么回事?

3 个答案:

答案 0 :(得分:12)

拆箱检查确切类型,如documentation中所述。

  

取消装箱是从类型对象到值的显式转换   键入或从接口类型到实现该类型的值类型   接口。拆箱操作包括:

     
      
  • 检查对象实例以确保它是盒装值   给定的值类型。

  •   
  • 将实例中的值复制到value-type变量中。

  •   

如您所见,第一步是检查对象实例是否与目标类型匹配。

同样引用文档:

  

要使值类型的取消装箱在运行时成功,则该项目为   unboxed必须是对先前创建的对象的引用   通过装箱该值类型的实例。试图取消装箱null   导致NullReferenceException。试图取消对...的引用   不兼容的值类型会导致InvalidCastException。

因此,要修复此错误,请确保在尝试取消装箱之前类型匹配:

object thirdTest = Convert.ToInt16(0);
short thirdtest2 = (short)thirdTest;  

答案 1 :(得分:9)

究竟发生了什么。

在第一种情况下,您有一个简短的未装箱的,然后您明确地将其转换为int。这是编译器知道如何操作的有效转换,因此它可以正常工作。

在第二种情况下,你有一个int,boxed,它们正在分配给一个int。这是一个整数的简单拆箱,它也有效,所以它可以工作。

在第三种情况下,你有一个简短的盒子,你试图将其拆箱到一个非短的变量。这不是有效的操作:您无法一步完成此操作。这也不是一个不常见的问题:如果您使用的是包含SqlDataReader列的SMALLINT,则无法执行此操作:

    int x = (int)rdr["SmallIntColumn"];

以下任何一项都适用于您的第三个示例:

    object thirdTest = Convert.ToInt16(0);
    int thirdTest2 = Convert.ToInt32(thirdTest);
    int thirdTest3 = (int)(short)thirdTest;

答案 2 :(得分:4)

Int16是一种写short的奇特方式;那里没有装箱/拆箱,只是16位和32位整数之间的普通CLR转换。

允许使用相同类型的第二个案例框和取消框:值类型int被包装在object中,然后被解包。

第三种情况尝试取消收藏到不同的类型(int而不是short),这是不允许的。