为什么我会收到InvalidCastException?

时间:2011-03-15 08:57:37

标签: c# linq

我在c#

中有以下代码段
List<int> list = new List<int>() { 1, 23, 5, 3, 423, 3 };
            var query = list.Cast<double>().Select(d => d);
            try
            {
                foreach (var item in query)
                {
                    Console.WriteLine(item);

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);

            }

它编译得很完美,但是当我执行它时,我会遇到异常。

3 个答案:

答案 0 :(得分:10)

因为你是从int到double进行类型转换,所以它不是转换它是一个类型转换,这与在一般情况下将int转换为double时有所不同。

Cast<T>扩展方法使用IL指令unbox.any

虽然像这样的C#演员

var x = (double)42;

实际上是IL指令的结果

conv.r8 

从根本上将类型拆箱为不同的类型是错误的,这就是你获得例外的原因。

This问题有相同的答案,也链接到Eric Lippert的blog post

答案 1 :(得分:6)

list包含ints,您尝试将其转换为double。将您的查询更改为

var query = list.Select(d => (double)d);

<强>更新

以下是Enumerable.Cast(.NET 4)的来源:

public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) { 
    IEnumerable<TResult> typedSource = source as IEnumerable<TResult>;
    if (typedSource != null) return typedSource; 
    if (source == null) throw Error.ArgumentNull("source");
    return CastIterator<TResult>(source);
}

static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source) {
    foreach (object obj in source) yield return (TResult)obj; 
} 

正如您所看到的,CastIterator尝试将object(在这种情况下为int}加注成double。如果目标类型与装箱的原始类型完全相同,则取消装箱操作仅会成功,因此会引发异常。 John Leidegren提供的This link详细解释了。

答案 2 :(得分:2)

.NET Framework类型转换和C#类型转换之间存在差异。他们不一样。 “将”转换为“int”是C#语言的一个特性,仅仅是语言的一个特征。

为此,C#编译器可以使用特殊指令将int转换为double。编译器在编译时知道源类型是“int”,目标类型是“double”,因此可以生成正确的指令。这实际上不是.NET Framework意义上的类型转换。

System.Int32无法类型转换为System.Double。编译Cast扩展方法时不知道源和目标集合的确切类型,因此没有生成处理 C#特定功能的特殊指令。为Cast扩展方法生成的唯一代码是普通的.NET类型转换(将类转换为其基类型,转换为对象,并将类型转换为它们实现的接口)。