Gilles jr Bisson
Gilles jr Bisson

Reputation: 533

Why can't C# cast an object containing a boxed int to a double?

In C#, why does Example 1 work:

int myValue1 = 11;
double resultDirectlyFromInt = myValue1;

But Example 2 does not:

int myValue2 = 22;
object myObject2 = myValue2;
double resultFromBoxedInt = (double)myObject2;

Yet again Example 3 does work:

double myValue3 = 33.3;
object myObject3 = myValue3;
double resultFromBoxedDouble = (double)myObject3;

Can someone explain the rationale behind that ? Because to me, working examples 1 and 3 look like proofs that example 2 should work.

Upvotes: 1

Views: 533

Answers (2)

WWW
WWW

Reputation: 63

Your first example is actually calling the operator called implicit conversion operator, which you can find more info in this link, and this happen to be implemented in compiler level. The reason why it works is compiler knows that Int32 integers can be represent fully in a Double-type variable during compile time.

In your example 2, the reason why it does not work is it during unbox, you must cast it back to the original type first, so that the runtime can ensure the type safety. Reference to other answers as well. Instead, you can change the example 2 as below so that it will run without runtime complaining, which is kind of explaining how example 1 works under-the-hood with the cast to double, but explicitly.

int myValue2 = 22;
object myObject2 = myValue2;
double resultFromBoxedInt = (double)(int)myObject2;

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1504122

Because to me, working examples 1 and 3 look like proofs that example 2 should work.

No, they're very different conversions.

C# defines a conversion from int to double (see section 10.2.3 of the C# 7 draft standard). But unboxing conversions are defined very differently, in section 10.3.7:

An unboxing operation to a non_nullable_value_type consists of first checking that the object instance is a boxed value of the given non_nullable_value_type, and then copying the value out of the instance.

...

If the source operand is a reference to an incompatible object, a System.InvalidCastException is thrown.

In your example 2, the object instance is not a boxed value of type double - it's a boxed value of type int, so the check described above fails.

As it happens, the .NET CLR is a little more forgiving in terms of unboxing than C# requires; you can unbox from a boxed int to a uint or vice versa, and also from an enum to its underlying type or vice versa. But it doesn't permit anything that requires a representation change, like int to double.

If you want a justification for those rules, think of it this way: in order to perform any conversion that performs real work (as opposed to just copying a bit pattern from one place to another), the compiler needs to tell the CLR which conversion to perform. For an unboxing operation, the actual type is only known at execution time, so the compiler can't instruct the CLR what to do. The CLR could have more complex rules so that it could perform the conversion based on the execution-time type - but that's straying into territory that is usually language-based.

Upvotes: 5

Related Questions