2013-11-22 74 views
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.有时,该值将为对象​​{decimal},T将为double,在这种情况下,将抛出InvalidCastException。但原则上这不应该是一个问题,因为值是一个十进制数(虽然被对象装箱),可以将其加倍。

我该如何处理这个问题?

回答

10

您只能将盒装值类型返回以确定类型已装箱。无论是从盒装类型还是从您正在投射的内容进行隐式或显式转换都无关紧要 - 您仍然必须投入盒装类型(为了取消箱),然后从那里拿走。

在这个例子中,这意味着两个连续的石膏:

double dd = (double) (decimal) o; 

或者使用Convert方法:

double dd = Convert.ToDouble(o); 

当然,这不会为您的实际使用情况下做的,因为你不能立即从泛型类型参数变为ToDouble。但只要目标类型为IConvertible,你可以这样做:

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

在泛型类型参数T可以取代double

3

后者不起作用,因为十进制值被装箱到一个对象中。这意味着获得值回你必须拆箱首先使用的相同的语法铸造,所以你必须这样做,在2个步骤是这样的:

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)); 
    } 
} 

您的代码不工作一直深受其他人对这个职位解释原因。