为什么Cast <double>()不能在IEnumerable <int>上工作?

dom*_*nic 6 .net c# ienumerable casting type-conversion

可能重复:
Enumerable.Cast <T>扩展方法无法从int转换为long,为什么?
令人困惑的Enumerable.Cast InvalidCastException
将IEnumerable <T>转换/转换为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()));
        }
    }
Run Code Online (Sandbox Code Playgroud)

}

Adr*_*scu 11

问题来自于在编译时解析了转换操作符(重载).试着想一下Cast是如何实现的.我打赌代码看起来像这样:

public static IEnumerable<T> Cast<T>(this IEnumerable source)
{
   foreach(object element in source)
   {
      yield return (T)(object)element;
   }
}
Run Code Online (Sandbox Code Playgroud)

编译器拥有的所有信息都是需要将对象强制转换为类型T.为此,它将使用默认的继承强制转换.不会使用自定义重载运算符.在您的示例中,int不是double,因此转换将失败.

选择示例:

source.Select(a => (double)a));
Run Code Online (Sandbox Code Playgroud)

因为编译器知道这两种类型并且它能够调用适当的重载操作符,所以可以正常工作.


Joh*_*n K 2

尝试使用 Array 类的 Convertall 方法。它使您可以明确控制转换。

var doubleArray = Array.ConvertAll<int, double>(intArray, num => (double)num);
Run Code Online (Sandbox Code Playgroud)

这会绕过您遇到的内部错误。

其他方法也可以让您明确控制转换过程。