Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OOC: What is the difference between ToList() and casting to List<T> in .NET?

OOC: Out Of Curiosity

So, as a little exercise and for the sake of learning, I decided to check if I was able to implement a very basic recursive function that would return a List<int>, but with the following restrictions:

1- The result should be returned by the function itself (as opposed to passed as an argument to a void function).

2 - No local "named" variables declared in the function's body.

I came up with the solution below (BTW: can this be improved in any way?)

While doing this, I learnt that ToList() is not the same thing as casting to List<T> (see example below) - Anyone out there who can explain what happens under the hood and what the difference between the two is?

Thanks!

PS - I'm using version 4.0 (in case it matters).

EDIT: the runtime error is Unable to cast object of type '<ConcatIterator>d__71'1[System.Int32]' to type 'System.Collections.Generic.List'1[System.Int32]'

public static List<int> SomeIntegers(int min, int max)
{
    //assume max >= min for simplicity  
    if (min == max)
        return new List<int>() { min };

    // runtime error 
    //return (List<int>)(SomeIntegers(min, max - 1).Concat(new List<int>() { max }));   

    //works
    return (SomeIntegers(min, max - 1).Concat(new List<int>() { max })).ToList(); 
}
like image 493
d.. Avatar asked Jan 21 '10 05:01

d..


3 Answers

ToList() is not the same as (casting) to List.

ToList() takes any IEnumerable (Lists, Arrays, Dictionaries, Sets, etc) and turns it into a List.

Casting to List takes an object that is already a list of some sort, and labels it as a list. example:

// fail -- arrays are not lists
var not_a_list = (List<int>)int[];
// success: arrays *are* IEnumerable, so you can convert them to a list.
var list_from_array = new [] { 1,2,3,4,5 }.ToList();
// success: WorkflowRoleCollection derives from List<WorkflowRole>
var derived_from_list = (List<WorkflowRole>) new WorkflowRoleCollection();

In your case, Concat() returns an IEnumerable, and not a List. Remember that it has to support generators (which are lazy-evaluated), so it doesn't make sense for it to be anything like a list underneath.

Btw, have you taken a look at the built-in function Enumerable.Range ?

like image 147
Jimmy Avatar answered Nov 02 '22 21:11

Jimmy


  • Casting only works if you actually have a List<T>, something derived from List<T>, or something with a valid type conversion to List<T>, otherwise it fails with an InvalidCastException. ToList() works on any IEnumerable.
  • ToList() always creates a new copy of the list even if you already have a list. Casting something to List<T> typically does not produce a copy of the list - it just gives you a new compile-time type for the same object.
like image 29
Mark Byers Avatar answered Nov 02 '22 20:11

Mark Byers


By the way, the best way to generate a list of integers is:

Enumerable.Range(min, length);

or

Enumerable.Range(min, max-min+1);

But that doesn't help you learn, so kudos to you! :)

like image 2
Michael Bray Avatar answered Nov 02 '22 21:11

Michael Bray