6

Possible Duplicate:
IEnumerable.Cast<>

One can implicitly convert from int to double. Why does "Specified cast is not valid." exception is raised here?

 double[] a = Enumerable.Range(0, 7).Cast<double>().ToArray();

I have tried several "versions" of it.

P.S. I know possible solutions like:

 double[] a = Enumerable.Range(0, 7).Select(x => (double)x).ToArray();

But I'm curious how Cast works => why it doesn't work in this example which looks so obvious.

Community
  • 1
  • 1
MajesticRa
  • 13,770
  • 12
  • 63
  • 77

2 Answers2

4

Cast is made to turn an IEnumerable (untyped) to an IEnumerable<T> (generically typed). It won't actually differently-cast any of the members.

Per this answer:

Well, you have incorrect expectations of Cast, that's all - it's meant to deal with boxing/unboxing, reference and identity conversions, and that's all. It's unfortunate that the documentation isn't as clear as it might be

So, you're stuck with .Select().

Community
  • 1
  • 1
eouw0o83hf
  • 9,438
  • 5
  • 53
  • 75
  • In light of this, how does the "cast" `int x = 42; double d = (double)x;` work? –  Mar 20 '12 at 21:47
  • 3
    Wouldn't it me more appropriate to close this question as a duplicate instead of providing the accepted answer from the question you link to? – Brian Rasmussen Mar 20 '12 at 21:49
  • +1 Btw: Select is faster than Cast, tested it multiple times. – Felix K. Mar 20 '12 at 21:52
  • 1
    @pst: Casts like that are actually compiled as "Convert" instructions. As BFree points out, the system doesn't know to perform this conversion when you're unboxing. – StriplingWarrior Mar 20 '12 at 21:53
4

The reason this fails is because essentially you're doing this:

        int x = 10;
        object f = x;
        double d = (double) f;

The int is getting boxed into the object, and when you go to unbox it, you're trying to unbox it to a double.

More specifically, here's the implementation of Cast:

public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
{
    IEnumerable<TResult> enumerable = source as IEnumerable<TResult>;
    if (enumerable != null)
    {
        return enumerable;
    }
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    return Enumerable.CastIterator<TResult>(source);
}

private static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source)
{
    foreach (object current in source)
    {
        yield return (TResult)current;
    }
    yield break;
}

As you can see, it's looping through the IEnumerable and boxing each element in the source. It then tries to unbox at which point you blow up.

BFree
  • 102,548
  • 21
  • 159
  • 201