views:

165

answers:

3

When a value type is boxed, it is placed inside an untyped reference object. So what causes the invalid cast exception here?

long l = 1;
object obj = (object)l;
double d = (double)obj;
+11  A: 

No, it's not placed in an untyped object. For each value type, there's a boxed reference type in the CLR. So you'd have something like:

public class BoxedInt32 // Not the actual name
{
    private readonly int value;
    public BoxedInt32(int value)
    {
        this.value = value;
    }
}

That boxed type isn't directly accessible in C#, although it is in C++/CLI. Obviously that knows the original type. So in C# you have to have a compile-time type of object for the variable but that doesn't mean that's the actual type of the object.

See the ECMA CLI spec or CLR via C# for more details.

Jon Skeet
Intersting, thanks Jon. Wagner's Effective C# states: "Boxing places a value type in an untyped reference object". I'm pretty sure it also says something to the effect that boxed objects don't contain any type metadata, though I can't find that particular quote right now. It was when reading that book that the question occured to me.
fearofawhackplanet
@fearofawhackplanet: I wouldn't like to put words into Bill's mouth about exactly what he meant by that - but the box object most definitely *does* know its original type, including enums. (Box an enum value and then use ToString directly with no unboxing for proof of that :)
Jon Skeet
I believe a good demonstration is this. `long l = 40L; object o = (object)l; Console.WriteLine(o.GetType());` In this case, System.Int64 is printed to the screen. Even though `o` is an object, the underlying type is still a long.
Anthony Pegram
+4  A: 

Jon Skeet's answer covers the why; as for the how to get around it, here's what you have to do:

long l = 1;
object obj = (object)l;
double d = (double)(long)obj;

The reason for the dual cast is this; when .NET unboxes the variable, it only knows how to unbox it into the type it was boxed from (long in your example.) Once you've unboxed it and you have a proper long primitive, you can then cast it to double or any other type castable from long.

Adam Maras