考虑以下枚举声明和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();
仅当原始数据是一个不起作用的数组时才会出现。
答案 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();