从对象框类型的通用铸造

时间:2013-11-22 13:36:23

标签: c# generics casting boxing unboxing

为什么这样做:

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.有时,值将是对象{decimal},T将是double,在这种情况下将抛出InvalidCastException。但原则上这不应该是一个问题,因为值是一个十进制(虽然是一个对象的盒子),可以强制转换为double。

我如何处理这个问题?

3 个答案:

答案 0 :(得分:11)

您只能将装箱值类型转换回到装箱的确切类型。如果从装箱类型到您正在投射的类型之间存在隐式或显式转换,则无关紧要to - 你仍然需要转换为盒装类型(为了取消装箱),然后从那里拿走它。

在示例中,这意味着两个连续的演员表:

double dd = (double) (decimal) o;

或者,使用Convert方法:

double dd = Convert.ToDouble(o);

当然,这不适用于您的实际用例,因为您无法立即从泛型类型参数转到ToDouble。但只要目标类型为IConvertible,您就可以执行此操作:

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

其中泛型类型参数T可以替换double

答案 1 :(得分:3)

后者不起作用,因为十进制值被装入一个对象。这意味着要获得价值,您必须先使用投射的相同语法进行拆箱,因此您必须按照以下两个步骤执行此操作:

double dd = (double) (decimal) o;

请注意,第一个(decimal)是拆箱,(double)正在投放。

答案 2 :(得分: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));
    }
}

您的代码不起作用的原因已在本文中得到其他人的充分解释。