为什么我会收到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
,您尝试ints
为double
。 将您的查询更改为
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类型转换(将类转换为其基类型,转换为对象,并将类型转换为它们实现的接口)。