一般性地从对象装箱类型转换

4
为什么这个可以工作:
decimal dec = new Decimal(33);
double dd = (double) dec;
Console.WriteLine(dd);

但不包括这个:
decimal dec = new Decimal(33);
object o = (object)dec;
double dd = (double) o;
Console.WriteLine(dd);

第二个例子抛出了以下异常:

System.InvalidCastException: 指定的转换无效。

这个问题源自一个情况,我有一个泛型方法。
public T GetValue(string q)

该方法从数据源获取值。这些值的类型是未知的,但该方法假设它可以将值强制转换为T。有时候值会是object{decimal}和T会是double,在这种情况下会抛出InvalidCastException异常。但原则上这不应该是一个问题,因为该值是一个十进制数(尽管被封装在对象中),可以强制转换为double。

我如何以一般化的方式处理这个问题?

3个回答

12
你只能将装箱的值类型强制转换回被装箱的确切类型。无论从装箱类型到你要转换的类型是否存在隐式或显式转换,你仍然需要先将其强制转换为装箱类型(以便取消装箱),然后再进行下一步操作。
在这个例子中,这意味着需要进行两次连续的强制转换:
double dd = (double) (decimal) o;

或者,使用 Convert 方法:
double dd = Convert.ToDouble(o);

当然,这对于您的实际用例来说是不够的,因为您不能立即从通用类型参数转换为 ToDouble。但只要目标类型是 IConvertible,您可以这样做:
double dd = (double)Convert.ChangeType(o, typeof(double));

泛型类型参数 T 可以替换为 double


3
后者无法工作,因为十进制值被封装到一个对象中。这意味着要想获得该值,首先必须使用相同的转换语法进行拆箱操作,因此您需要像这样分两步完成:
double dd = (double) (decimal) o;

请注意,第一个 (decimal) 是拆箱操作,而第二个 (double) 是强制类型转换。

2
这可以使用Convert.ChangeType来完成:
class Program
{
    static void Main(string[] args)
    {
        decimal dec = new Decimal(33);
        object o = (object)dec;
        double dd = GetValue<double>(o);
        Console.WriteLine(dd);
    }

    static T GetValue<T>(object val)
    {
        return (T)Convert.ChangeType(val, typeof(T));
    }
}

其他人在这篇文章中已经很好地解释了代码不起作用的原因。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接