我很难理解这一点。请考虑以下示例:
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'
的值。
这到底是怎么回事?
答案 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
),这是不允许的。