令人费解的Enumerable.Cast InvalidCastException

jas*_*son 44 .net c# exception

以下抛出一个InvalidCastException.

IEnumerable<int> list = new List<int>() { 1 };
IEnumerable<long> castedList = list.Cast<long>();
Console.WriteLine(castedList.First());
Run Code Online (Sandbox Code Playgroud)

为什么?

我正在使用Visual Studio 2008 SP1.

Mat*_*ton 60

那很奇怪!有一个博客张贴在这里,描述了如何的行为Cast<T>().NET 3.5和.NET 3.5 SP1,但它仍然无法解释InvalidCastException的,如果你这样重写你的代码,你甚至间已改变:

var list = new[] { 1 };
var castedList = from long l in list select l;
Console.WriteLine(castedList.First());
Run Code Online (Sandbox Code Playgroud)

显然你可以通过自己做演员来解决它

var castedList = list.Select(i => (long)i);
Run Code Online (Sandbox Code Playgroud)

这是有效的,但它并不首先解释错误.我尝试将列表转换为short和float,然后抛出相同的异常.

编辑

该博客文章确实解释了为什么它不起作用!

Cast<T>()是一种扩展方法,IEnumerable而不是IEnumerable<T>.这意味着当每个值到达它所投射的点时,它已经被装箱回System.Object.本质上,它试图这样做:

int i = 1;
object o = i;
long l = (long)o;
Run Code Online (Sandbox Code Playgroud)

此代码抛出您正在获取的InvalidCastException.如果你试图直接将一个int转换为long,那么将一个盒装的int转换为long也行不通.

当然怪异!

  • @Timwi:对不起,但没有.请参阅我对上述评论的评论. (5认同)
  • +1 - 我有这个确切的问题,阅读博客,无法解决.您的编辑清除了它.大! (2认同)
  • 根本没什么奇怪的.`.Cast <T>`做**演员**.从int到long**的转换不是转换**.令人遗憾的是,C#选择对不同的操作使用相同的语法. (2认同)

oku*_*ane 27

Enumerable.Cast方法定义如下:

public static IEnumerable<TResult> Cast<TResult>(
    this IEnumerable source
)
Run Code Online (Sandbox Code Playgroud)

并且没有关于IEnumerable项的初始类型的信息,所以我认为你的每个int最初都是通过装箱转换为System.Object,然后它被尝试拆箱成长变量,这是不正确的.

类似的代码重现这个:

int i = 1;
object o = i; // boxing
long l = (long)o; // unboxing, incorrect
// long l = (int)o; // this will work
Run Code Online (Sandbox Code Playgroud)

因此,您的问题的解决方案将是:

ints.Select(i => (long)i)
Run Code Online (Sandbox Code Playgroud)