Search code examples
c#genericscastingboxingunboxing

generic casting from object-boxed type


Why does this work:

decimal dec = new Decimal(33);
double dd = (double) dec;
Console.WriteLine(dd);

But not this:

decimal dec = new Decimal(33);
object o = (object)dec;
double dd = (double) o;
Console.WriteLine(dd);

The second example throws:

System.InvalidCastException: Specified cast is not valid.

This question comes from a situation where I have a generic method

public T GetValue(string q)

That gets values from a datasource. The types of these values are unknown, but the method assumes that it can cast the value to T. Sometimes the value will be object{decimal} and T will be double, in which case the InvalidCastException will be thrown. But in principle this should not be an issue since the value is a decimal (albeit boxed by an object) which can be cast to double.

How do I handle this generically?


Solution

  • You can only cast boxed value types back to the exact type that was boxed in. It doesn't matter if there is an implicit or explicit conversion from the boxed type to the one you are casting to -- you still have to cast to the boxed type (in order to unbox) and then take it from there.

    In the example, this means two consecutive casts:

    double dd = (double) (decimal) o;
    

    Or, using the Convert methods:

    double dd = Convert.ToDouble(o);
    

    Of course this won't do for your real use case because you cannot immediately go from a generic type parameter to ToDouble. But as long as the target type is IConvertible, you can do this:

    double dd = (double)Convert.ChangeType(o, typeof(double));
    

    where the generic type parameter T can be substituted for double.