简体   繁体   中英

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())

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.

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 IEnumerable s, etc.

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

The Where extension filters and returns IEnumerable<TSource> hence you need to call .ToList() to convert it back

public List<Customer> FilterCustomersByStatus(List<Customer> source, string status)
{
    return source.Where(c => c.Status == status).ToList();//This will return a list of type customer
}

The difference between IEnumerable and IList is, the enumerable doesn't contain any data, it contains an iterator that goes through the data as you request the new one (for example, with a foreach loop). On the other hand, the list is a copy of the data. In your case, to create the List, ToList() method iterates through the entire data and adds them to a List object.

Depending to the usage you are planning, both have advantages and disadvantages. For example, if you are planning to use the entire data more than once, you should go with the list, but if you are planning to use it once or you are planning to query it again using linq, enumerable should be your choice.

Edit: The answer to the question why the return type of Where is WhereListIterator instead of List is, it's partly because how Linq works. For example, if you had another Where or another Linq statement following the first, the compiler would create a single query using the entire method chain, then return the iterator for the final query. On the other hand, if the first Where would return a List that would cause each Linq method in the chain execute separately on the data.

Try this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM