You can only unbox a value type to its original type (and the nullable version of that type).
By the way, this is valid (just a shorthand for your two line version):
object i = 4;
decimal d = (decimal)(int)i; // works even w/o decimal as it's a widening conversion
For the reason behind this read this Eric Lippert’s blog entry: Representation and Identity
Personally, I categorize things done by cast syntax into four different types of operation (they all have different IL instructions):
- Boxing (
box
IL instruction) and unboxing (unbox
IL instruction) - Casting through the inhertiance hierarchy (like
dynamic_cast<Type>
in C++, usescastclass
IL instruction to verify) - Casting between primitive types (like
static_cast<Type>
in C++, there are plenty of IL instructions for different types of casts between primitive types) - Calling user defined conversion operators (at the IL level they are just method calls to the appropriate
op_XXX
method).