为什么我会收到InvalidCastException?

我在c#中有以下代码片段

List list = new List() { 1, 23, 5, 3, 423, 3 }; var query = list.Cast().Select(d => d); try { foreach (var item in query) { Console.WriteLine(item); } } catch (Exception ex) { Console.WriteLine(ex.Message); } 

它编译得很完美,但是当我执行它时,我得到了exception。

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

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

虽然C#就像这样

 var x = (double)42; 

实际上导致了IL指令

 conv.r8 

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

这个问题有相同的答案,也链接到Eric Lippert的博客文章 。

list包含ints ,您尝试intsdouble 。 将您的查询更改为

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

更新

这是Enumerable.Cast (.NET 4)的源代码:

 public static IEnumerable Cast(this IEnumerable source) { IEnumerable typedSource = source as IEnumerable; if (typedSource != null) return typedSource; if (source == null) throw Error.ArgumentNull("source"); return CastIterator(source); } static IEnumerable CastIterator(IEnumerable source) { foreach (object obj in source) yield return (TResult)obj; } 

如您所见, CastIterator尝试将object (在本例中为boxed int )转换为double 。 如果目标类型与装箱的原始类型完全相同,则取消装箱操作仅会成功,因此会引发exception。 John Leidegren提供的这个链接详细解释。

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

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

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