8

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

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

我在运行时遇到的具体错误是如果我在 Visual Studio 中进行Specified cast is not valid. QuickWatch ,我会得到一个.(int)thirdTestCannot unbox 'thirdTest' as a 'int'

这到底是怎么回事?

4

3 回答 3

12

拆箱检查文档中解释的确切类型。

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

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

  • 将实例中的值复制到值类型变量中。

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

还从文档中引用:

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

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

object thirdTest = Convert.ToInt16(0);
short thirdtest2 = (short)thirdTest;  
于 2012-01-07T17:17:49.397 回答
9

正在发生的事情正是它所说的。

在第一种情况下,您有一个简短的未装箱的,然后您将其显式类型转换为 int。这是编译器知道如何进行的有效转换,因此它可以工作。

在第二种情况下,您有一个装箱的 int,它正在分配回一个 int。这是一个简单的整数拆箱,这也是有效的,所以它有效。

在第三种情况下,您有一个短的、装箱的,即您试图将其拆箱成一个不是短的变量。这不是一个有效的操作:你不能一步完成。这也不是一个不常见的问题:例如,如果您使用的SqlDataReader是包含SMALLINT列的 a,则不能:

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

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

    object thirdTest = Convert.ToInt16(0);
    int thirdTest2 = Convert.ToInt32(thirdTest);
    int thirdTest3 = (int)(short)thirdTest;
于 2012-01-07T17:18:49.410 回答
4

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

第二种情况将装箱和拆箱到相同的类型,这是允许的:值类型int被包装在 anobject中,然后被拆开。

第三种情况尝试将其拆箱为不同的类型(int而不是short),这是不允许的。

于 2012-01-07T17:19:19.040 回答