4

Why there is InvalidCastException thrown? Can someone describe me this behavior?

object zero = 0;
decimal? dec = (decimal?)zero;
Przemaas
  • 841
  • 11
  • 23

2 Answers2

15

A boxed int can only be unboxed to an int. This, however, is legal:

object zero = 0;
decimal? dec = (decimal?)(int)zero;

See MSDN or the ECMA 334 C# spec for details. The key here is the following:

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:

  1. Checking the object instance to make sure that it is a boxed value of the given value type.
  2. Copying the value from the instance into the value-type variable.

Edit: This linked article is worth pulling out of the comments. Thanks Rob Kennedy!

jason
  • 236,483
  • 35
  • 423
  • 525
  • Ok, but why such interim casting is necessary? – Przemaas Jul 09 '09 at 13:39
  • The first cast (int) unboxes the boxed int to a value type of type int (this is a legal operation). The second cast (decimal?) casts the resulting int to decimal?. – jason Jul 09 '09 at 13:41
  • Microsoft (for good reason) never wrote a implicit cast overload for object to decimal. – Michael Meadows Jul 09 '09 at 13:42
  • 1
    @Michael Meadows: This is legal: object zero = 0m; decimal? dec = (decimal)zero; Note the 'm' explicitly telling the compiler that the literal "0" is to be interpreted as a decimal. – jason Jul 09 '09 at 13:44
  • @Jason, a decimal is an object, so the first example is polymorphism. The second example is explicit casting. What I was saying was to answer @Przemaas' comment. You must explicitly cast the "zero" variable to int first, because you cannot implicitly cast an object to int, and since it's not an INullable, the explicit cast directly to that type fails. – Michael Meadows Jul 09 '09 at 13:48
  • @Michael Meadows: Either I misread your comment, or you deleted it and changed "explicit" to "implicit." I initially read your comment to state that there was no explicit cast from object to decimal. Apologies if I misread. – jason Jul 09 '09 at 13:50
  • 3
    Eric Lippert goes into quite some detail about why this works the way it does. The summary: Unboxing to anything but the original type would involve *a lot* of generated code for all the different possibilities since the compiler doesn't know what the original boxed type is. http://blogs.msdn.com/ericlippert/archive/2009/03/19/representation-and-identity.aspx – Rob Kennedy Jul 09 '09 at 14:15
  • @Rob : I was looking for this post but wasn't able to find it... thanks ;) – Thomas Levesque Jul 09 '09 at 14:25
0

See this article http://msdn.microsoft.com/en-us/magazine/cc301569.aspx

Specifically "The common language runtime first ensures that the reference type variable is not null and that it refers to an object that is a boxed value of the desired value type. If either test fails, then an InvalidCastException exception is generated."

I think you are failing on the object of that value. I think the coversion to int works because that 0 literal will convert to an int and then an int converts to decimal.

If you do this it works

    decimal? test=0;
    object zero = test;
    decimal? dec = (decimal?)zero;

But I think the "0" in your snippet is not a "decimal" type.

I am still not positive cause this gets the same exception.

        int test=0;
        object zero = test;
        decimal? dec = (decimal?)zero;
Maestro1024
  • 3,173
  • 8
  • 35
  • 52
  • My problem originally comes from below method: public TResult Convert(object value) { try { return (TResult)value; } catch (InvalidCastException) { return default(TResult); } } This method returns null when called: Convert(0); I cann't make any assumptions about TResult and I don't know what exactly comes as an argument. That is why I cannot use Convert.To...() goodies. – Przemaas Jul 09 '09 at 14:32