可能重复:
Enumerable.Cast<T> extension method fails to cast from int to long, why ?
Puzzling Enumerable.Cast InvalidCastException
Cast/Convert IEnumerable<T> to IEnumerable<U> ?
我正在尝试将整数数组转换为双精度数组(因此我可以将它传递给一个带有双精度数组的函数)。
最明显的解决方案(对我来说,至少)是对IEnumerable使用Cast扩展函数,但它给了我一个InvalidCastException,我不明白为什么。我的解决方法是使用Select,但我认为Cast看起来更整洁。
有人能告诉我为什么Cast方法不起作用吗?
希望以下代码说明我的问题:
namespace ConsoleApplication1
{
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
var intArray = new[] { 1, 2, 3, 4 };
PrintEnumerable(intArray, "intArray: ");
var doubleArrayWorks = intArray.Select(x => (double)x).ToArray();
PrintEnumerable(doubleArrayWorks, "doubleArrayWorks: ");
// Why does this fail??
var doubleArrayDoesntWork = intArray.Cast<double>().ToArray();
PrintEnumerable(doubleArrayDoesntWork, "doubleArrayDoesntWork: ");
// Pause
Console.ReadLine();
}
private static void PrintEnumerable<T>(
IEnumerable<T> toBePrinted, string msgPrefix)
{
Console.WriteLine(
msgPrefix + string.Join(
",", toBePrinted.Select(x => x.ToString()).ToArray()));
}
}
}
答案 0 :(得分:10)
问题来自于在编译时解析了转换操作符(重载)。 试着想一下Cast是如何实现的。我打赌代码看起来像这样:
public static IEnumerable<T> Cast<T>(this IEnumerable source)
{
foreach(object element in source)
{
yield return (T)(object)element;
}
}
编译器拥有的所有信息都是需要将对象强制转换为类型T.为此,它将使用默认的继承强制转换。不会使用自定义重载运算符。在你的例子中,int不是double,因此转换会失败。
选择示例:
source.Select(a => (double)a));
有效,因为编译器知道这两种类型,并且能够调用适当的重载运算符。
答案 1 :(得分:2)
尝试使用Array类的Convertall方法。它可以让您明确控制转换。
var doubleArray = Array.ConvertAll<int, double>(intArray, num => (double)num);
这会绕过您遇到的内部错误。
其他方法也可以让您明确控制转换过程。