49

Why this explicit cast does throw Specified cast is not valid. exception ?

decimal d = 10m;
object o = d;
int x = (int)o;

But this works:

int x = (int)(decimal)o;
Homam
  • 23,263
  • 32
  • 111
  • 187
  • 1
    possible duplicate of [Why can't I unbox an int as a decimal?](http://stackoverflow.com/questions/1085097/why-cant-i-unbox-an-int-as-a-decimal) – nawfal Nov 29 '13 at 06:38
  • Other questions/duplicates all combining to a full answer: [Why can't I unbox an int as a decimal?](https://stackoverflow.com/q/1085097/11683), [Cast object containing int to float results in InvalidCastException](https://stackoverflow.com/q/24447387/11683), [Casting object to int throws InvalidCastException in C#](https://stackoverflow.com/q/39891504/11683) – GSerg Jul 19 '19 at 08:08

4 Answers4

90

A boxed value can only be unboxed to a variable of the exact same type. This seemingly odd restriction is a very important speed optimization that made .NET 1.x feasible before generics were available. You can read more about it in this answer.

You don't want to jump through the multiple cast hoop, simple value types implement the IConvertible interface. Which you invoke by using the Convert class:

        object o = 12m;
        int ix = Convert.ToInt32(o);
silkfire
  • 24,585
  • 15
  • 82
  • 105
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
23

When you do this, you're implicitly boxing the decimal d to a basic object:

object o = d;

You cannot cast boxed values directly without first unboxing them, which is why casting directly to an int, as in the following, fails:

int x = (int)o;

However, by doing this (intermediately casting to a decimal first):

int x = (int)(decimal)o;

You're first unboxing o, which means you're retrieving the decimal value, then casting the unboxed decimal value to an int, which works because C# supports casting decimals to ints.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
10

decimal has an explicit cast operator to int. object does not:

decimal d = 10m;
object o = d;
int x = (int)d;  // OK, calls decimal.explicit operator int(d).
int y = (int)o;  // Invalid cast.
Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
3

What you need to think of here is that boxing and unboxing is not exactly a kind of conversion. You just "wrap" the object type "around" the initial decimal-type. That is why you need to unbox the object first, before you are able to convert it to an integer.

Semyazas
  • 2,101
  • 14
  • 14