Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invalid cast from List<MyType> to IEnumerable<MyType> back to List<MyType>, why?

So basically i have this method.

public List<Customer> FilterCustomersByStatus(List<Customer> source, string status)
{
    return (List<Customer>)source.Where(c => c.Status == status);
}

I throws me an error that it cannot cast:

Unable to cast object of type 'WhereListIterator`1[AppDataAcces.Customer]' to type 'System.Collections.Generic.List`1[AppDataAcces.Customer]'.

Why...? since the underlying type is the same, does the Enumerable.Where create a new instance of WhereListIterator and if so why would anyone do this, because thats an unnecessary loss of performance and functionality since i always have to create a new list (.ToList())

like image 583
Freeman Avatar asked Jul 29 '12 16:07

Freeman


2 Answers

does the Enumerable.Where create a new instance of WhereListIterator

Yes.

and if so why would anyone do this

Because it allows lazy streaming behavior. Where won't have to filter all the list if its consumer wants only first or second entry. This is normal for LINQ.

because thats an unnecessary loss of performance and functionality since i always have to create a new list (.ToList())

That "loss of performance and functionality" comes from your design. You don't need List<Customer> after filtering, because it's pointless to do any modifications on it.

Update: "why is it implemented so" Because it it implemented over IEnumerable, not IList. And thus it looks like IEnumerable, it quacks like IEnumerable.

Besides, it's just so much easier to implement it this way. Imagine for a moment that you have to write Where over IList. Which has to return IList. What should it do? Return a proxy over original list? You'll suffer huge performance penalties on every access. Return new list with filtered items? It'll be the same as doing Where().ToList(). Return original list but with all non-matching items deleted? That's what RemoveAll is for, why make another method.

And remember, LINQ tries to play functional, and tries to treat objects as immutables.

like image 82
Serg Rogovtsev Avatar answered Oct 12 '22 11:10

Serg Rogovtsev


As others pointed out, you need to use ToList to convert the result to List<T>.

The reason is that Where is lazily evaluated, so Where does not really filter the data. What it does is create an IEnumerable which filters data as needed.

Lazy evaluation has several benefits. It might be faster, it allows using Where with infinite IEnumerables, etc.

ToList forces the result to be converted to List<T>, which seems to be what you want.

like image 21
luiscubal Avatar answered Oct 12 '22 11:10

luiscubal