Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why won't Cast<double>() work on IEnumerable<int>? [duplicate]

Possible Duplicates:
Enumerable.Cast<T> extension method fails to cast from int to long, why ?
Puzzling Enumerable.Cast InvalidCastException
Cast/Convert IEnumerable<T> to IEnumerable<U> ?

I'm trying to convert an array of integers to an array of doubles (so I can pass it to a function that takes an array of doubles).

The most obvious solution (to me, at least) is to use the Cast extension function for IEnumerable, but it gives me an InvalidCastException, and I don't understand why. My workaround is to use Select instead, but I think Cast looks neater.

Could someone tell me why the Cast method isn't working?

Hopefully the code below illustrates my problem:

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()));
        }
    }

}

like image 501
dominic Avatar asked Dec 08 '09 06:12

dominic


2 Answers

The problem comes from the fact that cast operators (overloaded) are resolved at compile time. Try to think how Cast is implemented. I bet the code looks like this:

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

All the info the compiler has is that it needs to cast an object to a type T. And for that it will use the default inheritance casting. No custom overloaded operator will be used. And in your example an int is not a double so the cast will fail.

The select example:

source.Select(a => (double)a));

works because the compiler knows both types and it's able to call the appropriate overloaded operator.

like image 121
Adrian Zanescu Avatar answered Sep 28 '22 02:09

Adrian Zanescu


Try using the Convertall method of the Array class. It gives you explicit control over the conversion.

var doubleArray = Array.ConvertAll<int, double>(intArray, num => (double)num);

This bypasses the internal error that you are experiencing.

Other methods give you explicit control over the conversion process too.

like image 33
John K Avatar answered Sep 28 '22 01:09

John K