Why object is int [duplicate]
I understand what boxing is. A value type is boxed to an object/reference type and is then stored on managed heap as an object. But I can't get thru unboxing.
Unboxing converts your object/reference type back to the value type
int i = 123; // A value type
object box = i; // Boxing
int j = (int)box; // Unboxing
Alright. But if I try to unbox a value type into another value type, for example, long in above example, it throws InvalidCastException
long d = (long)box;
It leaves me with an idea that may be runtime implicitly knows the actual TYPE of value type boxed inside "box" object. If I am right, I wonder where this type information is stored.
EDIT:
Since int
is implicitly convertible to long
. This is what confusing me.
int i = 123;
long lng = i;
is perfectly fine because it has no boxing/unboxing involved.
Solution 1:
When a value is boxed it gets an object header. The kind that any type that derives from System.Object has. The value follows that header. The header contains two fields, one is the "syncblk", it has various uses that are beyond the scope of the question. The second field describes the type of object.
That's the one you are asking about. It has various names in literature, most commonly "type handle" or "method table pointer". The latter is the most accurate description, it is a pointer to the info the CLR keeps track of whenever it loads a type. Lots of framework features depend on it. Object.GetType() of course. Any cast in your code as well as the is and as operators use it. These casts are safe so you can't turn a Dog into a Cat, the type handle provides this guarantee. The method table pointer for your boxed int points to the method table for System.Int32
Boxing was very common in .NET 1.x, before generics became available. All of the common collection types stored object instead of T. So putting an element in the collection required (implicit) boxing, getting it out again required explicit unboxing with a cast.
To make this efficient, it was pretty important that the jitter didn't need to consider the possibility that a conversion would be required. Because that requires a lot more work. So the C# language included the rule that unboxing to another type is illegal. All that's needed now is a check on the type handle to ensure it is expected type. The jitter directly compares the method table pointer to the one for System.Int32 in your case. And the value embedded in the object can be copied directly without any conversion concerns. Pretty fast, as fast as it can possibly be, this can all be done with inline machine code without any CLR call.
This rule is specific to C#, VB.NET doesn't have it. Typical trade-off between those two languages, C#'s focus is on speed, VB.NET on convenience. Converting to another type when unboxing isn't otherwise a problem, all simple value types implement IConvertible. You write it explicit in your code, using the Convert helper class:
int i = 123; // A value type
object box = i; // Boxing
long j = Convert.ToInt64(box); // Conversion + unboxing
Which is pretty similar to the code that the VB.NET compiler auto-generates.
Solution 2:
It's because boxing instruction adds value type token into result object MSDN. When you are unboxing value from object, this variable is known type (and size in memory). Therefore you must cast object to original value type.
In your example you even don't need to cast it from int to long, because it's an implicit cast.