I\'m having a hard time understanding this. Consider the following example:
protected void Page_Load(object sender, EventArgs e)
{
// No surprise that t
Int16
is a fancy way to write short
; there is no boxing/unboxing going on there, just the plain CLR conversion between 16-bit and 32-bit integers.
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.
The third case tries to unbox to a different type (int
instead of short
) which is not allowed.
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. Attempting to unbox a reference to an incompatible value type causes an 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. 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. 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:
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;