Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 617
Manolo Avatar asked Dec 02 '22 21:12

Manolo


2 Answers

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.

like image 182
Jon Avatar answered Dec 14 '22 23:12

Jon


The latter doesn't work because the decimal value is boxed into an object. That means to get the value back you have to unbox first using the same syntax of casting, so you have to do it in 2 steps like this:

double dd = (double) (decimal) o;

Note that the first (decimal) is unboxing, the (double) is casting.

like image 33
King King Avatar answered Dec 14 '22 23:12

King King