3

There have been a couple of times where I've been curious about the .Cast<T> LINQ extension method. I think to myself "that sounds like just what I need in this situation" but whenever I try to use it I always end up getting an InvalidCaseException. I have never been able to use this method successfully. Here's an example line which checks the exception:

Enumerable.Range(0,10).Cast<float>().ForEach(Console.Out.WriteLine);

There is nothing controversial about casting an int to a float, so why does this method refuse to do it? I can work around this and get the desired effect by simply replacing the .Cast<float> with a .Select(x => (float)x)

Enumerable.Range(0, 10).Select(x => (float)x).ForEach(Console.Out.WriteLine);

That isn't too much hassle, but still, I just don't get why the Cast<float> method can't do the job for me.

The question in a nutshell: How do you use the .Cast<T> extension method?

It's not relevant to the question, but just in case someone wants to know, I used a custom ForEach extension method in those code snippets up above (the standard one only works with lists):

static class Extensions
{
    public static void ForEach<T>(this IEnumerable<T> x, Action<T> l)
    {
        foreach (var xs in x) l(xs);
    }
}
tRuEsAtM
  • 3,517
  • 6
  • 43
  • 83
TheIronKnuckle
  • 7,224
  • 4
  • 33
  • 56
  • 4
    http://stackoverflow.com/questions/15394032/difference-between-casting-and-using-the-convert-to-method check this link nice explanation – Prasanna Kumar J Nov 22 '16 at 06:09

2 Answers2

3

If you look at ReferenceSource for the source code of Cast<TResult>method, you will see that in the end CastIterator<TResult> method is called which is something like:

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

As you see, C# tries to cast to TResult from boxed object and it is the reason of exception. If you want to imitate the problem try following:

int a = 5;
object o = a;
float f = (float)o;
Adil Mammadov
  • 8,476
  • 4
  • 31
  • 59
2

When you write the following:

int a = GetInt();
var b = (float)a;

You're not actually casting the value. You're converting it. C# just provides nice syntax for you. The IL generated here is conv.r4 which converts the value on the top of the stack to a float.

Enumerable.Cast<T> is actually performing a cast, and doesn't get the nicety of the syntactic sugar.

If you were to write:

Enumerable.Range(0,10).Cast<object>().ForEach(Console.Out.WriteLine);

You'd be fine, as an integer is castable to an object.

Rob
  • 26,989
  • 16
  • 82
  • 98
  • 2
    I think more details are needed. What's the difference between casting and converting? Why it can't always convert? Why it's not possible to create Cast extension which works like you would expect (or if possible, how?). – Evk Nov 22 '16 at 05:55