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();
}
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
?
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.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! :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With