简体   繁体   English

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

[英]C# - Issues with boxing / unboxing / typecasting ints. I don't understand

I'm having a hard time understanding this.我很难理解这一点。 Consider the following example:考虑以下示例:

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

The specific error that I get at runtime is Specified cast is not valid.我在运行时遇到的特定错误是Specified cast is not valid. If I QuickWatch (int)thirdTest in Visual Studio, I get a value of Cannot unbox 'thirdTest' as a 'int' .如果我在 Visual Studio 中使用 QuickWatch (int)thirdTest ,我会得到一个值Cannot unbox 'thirdTest' as a 'int'

What the heck is going on here?这到底是怎么回事?

Unboxing checks the exact type as explained in the documentation .拆箱检查文档中解释的确切类型。

Unboxing is an explicit conversion from the type object to a value type or from an interface type to a value type that implements the interface.拆箱是从类型对象到值类型或从接口类型到实现接口的值类型的显式转换。 An unboxing operation consists of:拆箱操作包括:

  • Checking the object instance to make sure that it is a boxed value of the given value type.检查对象实例以确保它是给定值类型的装箱值。

  • Copying the value from the instance into the value-type variable.将值从实例复制到值类型变量中。

As you can see the first step is to check that the object instance matches the target type.如您所见,第一步是检查对象实例是否与目标类型匹配。

Also quote from the documentation:还引用了文档:

For the unboxing of value types to succeed at run time, the item being unboxed must be a reference to an object that was previously created by boxing an instance of that value type.为了在运行时成功取消装箱值类型,被取消装箱的项必须是对先前通过装箱该值类型的实例创建的对象的引用。 Attempting to unbox null causes a NullReferenceException.尝试取消装箱 null 会导致 NullReferenceException。 Attempting to unbox a reference to an incompatible value type causes an InvalidCastException.尝试取消装箱对不兼容值类型的引用会导致 InvalidCastException。

So to fix this error make sure that the type matches before attempting to unbox:因此,要修复此错误,请在尝试取消装箱之前确保类型匹配:

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

What's going on is exactly what it says.正在发生的事情正是它所说的。

In the first case, you have a short, unboxed, that you are then explicitly typecasting to an int.在第一种情况下,您有一个简短的、未装箱的,然后您将其显式转换为 int。 This is a valid conversion that the compiler knows how to do, so it works.这是编译器知道如何进行的有效转换,因此它可以工作。

In the second case, you have an int, boxed, that are are assigning back to an int.在第二种情况下,您有一个装箱的 int,它们正在分配回一个 int。 This is a simple unboxing of an integer, which also valid, so it works.这是一个整数的简单拆箱,它也是有效的,所以它有效。

In the third case, you have a short, boxed, that are you trying to unbox into a variable that is not a short.在第三种情况下,你有一个短的,装箱的,你试图拆箱成一个不是短的变量。 This isn't a valid operation: you can't do this in one step.这不是有效的操作:您不能一步完成。 This is not an uncommon problem, either: if you are using, for example, a SqlDataReader that contains a SMALLINT column, you cannot do:这也不是一个不常见的问题:例如,如果您正在使用包含SMALLINT列的SqlDataReader ,则不能执行以下操作:

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

Either of the following should work in your third example:以下任一方法都适用于您的第三个示例:

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

Int16 is a fancy way to write short ; Int16是一种写short的奇特方式; there is no boxing/unboxing going on there, just the plain CLR conversion between 16-bit and 32-bit integers.那里没有装箱/拆箱,只有 16 位和 32 位整数之间的普通 CLR 转换。

The second case boxes and unboxes to the same type, which is allowed: value type int gets wrapped in an object , and then gets unwrapped.第二种情况装箱和拆箱为相同的类型,这是允许的:值类型int被包裹在一个object ,然后被解开。

The third case tries to unbox to a different type ( int instead of short ) which is not allowed.第三种情况尝试拆箱为不允许的不同类型( int而不是short )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM