如何使用IEnumerable.Cast<>和.ToArray()将int数组转换为枚举数组?

时间:2016-12-15 16:27:45

标签: c# .net linq ienumerable

考虑以下枚举声明和int数组:

enum Test { None };

int[] data = {0};

要将此int[]数组转换为Test[]数组,我们只需执行此操作:

Test[] result = Array.ConvertAll(data, element => (Test)element);

我最初试图这样做:

Test[] result = data.Cast<Test>().ToArray();

但是,它会在运行时抛出异常:

  

System.ArrayTypeMismatchException:无法将源数组类型分配给目标数组类型。

问题一

有没有办法在没有错误的情况下使用Linq和Cast<>执行此操作,或者我必须使用Array.Convert()吗?

问题二(在第一个问题得到正确回答后添加)

究竟为什么不起作用?

似乎这是一个实现细节逃逸的情况......考虑一下:

这会导致错误:

var result = data.Cast<Test>().ToList(); // Happens with "ToList()" too.

但这不是:

var result = new List<Test>();

foreach (var item in data.Cast<Test>())
    result.Add(item);

这两点都没有:

var result = data.Select(x => x).Cast<Test>().ToList();

明确的含义是在导致此异常的.ToList()实现中正在进行某种优化。

附录:

这也有效:

List<int> data = new List<int>{0};
var result = data.Cast<Test>().ToList();

List<int> data = new List<int>{0};
var result = data.Cast<Test>().ToArray();

仅当原始数据是一个不起作用的数组时才会出现。

3 个答案:

答案 0 :(得分:8)

您可以使用.Select(e => (Test)e)

答案 1 :(得分:1)

在这种情况下它不起作用,因为Cast首先执行以下检查:

public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
{
  IEnumerable<TResult> results = source as IEnumerable<TResult>;
  if (results != null)
    return results;
  // ... the rest of the method
}

事实证明,对于int[],此检查会成功(因此int[]IEnumerable<Test>不为空)。结果,Cast实际上什么也没做,它按原样返回数组。然后,当您致电ToArray时,会调用Array.Copy。它尝试从int[]数组复制到Test[]数组,并因类型不匹配而失败。你看到这个例外。

答案 2 :(得分:1)

因为演员实际上没有做任何事情,因为它认为该集合已经是欲望类型

    IEnumerable<Test> cast = data.Cast<Test>();
    IEnumerable<Test> select = data.Select(e => (Test) e);

    Console.WriteLine(cast == (IEnumerable<int>) data); //True
    Console.WriteLine(select == (IEnumerable<int>) data); //False
    Console.WriteLine(select == cast); //Flase

正如您所见,演员IEnumerable实际上只是原始数组。因此,.ToArray正在尝试执行与(Test[]) data.ToArray();

类似的操作