简体   繁体   English

来自List的无效演员表 <MyType> 到IEnumerable <MyType> 返回目录 <MyType> ,为什么?

[英]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]'. 无法将类型为'WhereListIterator`1 [AppDataAcces.Customer]'的对象转换为'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()) 由于底层类型是相同的,Enumerable.Where是否创建了WhereListIterator的新实例,如果是这样,为什么有人会这样做,因为这是不必要的性能和功能损失,因为我总是要创建一个新列表(.ToList( ))

does the Enumerable.Where create a new instance of WhereListIterator 是Enumerable.Where创建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. Where不会有如果消费者只想要第一或第二项过滤所有的名单。 This is normal for LINQ. 这对LINQ来说是正常的。

because thats an unnecessary loss of performance and functionality since i always have to create a new list (.ToList()) 因为这总是不得不创建一个新的列表(.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. 过滤后不需要List<Customer> ,因为对它进行任何修改都没有意义。

Update: "why is it implemented so" Because it it implemented over IEnumerable , not IList . 更新:“为什么这样实现”因为它是通过IEnumerable实现的,而不是IList And thus it looks like IEnumerable , it quacks like IEnumerable . 因此它看起来像IEnumerable ,它像IEnumerable一样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 . 想象一下,你必须写一个时刻WhereIList Which has to return IList . 哪个必须返回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() . 它与Where().ToList() Return original list but with all non-matching items deleted? 返回原始列表但删除了所有不匹配的项目? That's what RemoveAll is for, why make another method. 这就是RemoveAll的用途,为什么要制作另一种方法。

And remember, LINQ tries to play functional, and tries to treat objects as immutables. 请记住,LINQ尝试播放功能,并尝试将对象视为不可变的。

As others pointed out, you need to use ToList to convert the result to List<T> . 正如其他人所指出的,您需要使用ToList将结果转换为List<T>

The reason is that Where is lazily evaluated, so Where does not really filter the data. 原因是懒惰地评估了Where ,所以Where没有真正过滤数据。 What it does is create an IEnumerable which filters data as needed. 它的作用是创建一个IEnumerable ,根据需要过滤数据。

Lazy evaluation has several benefits. 懒惰评估有几个好处。 It might be faster, it allows using Where with infinite IEnumerable s, etc. 它可能更快,它允许使用Where无限IEnumerable s等。

ToList forces the result to be converted to List<T> , which seems to be what you want. ToList强制将结果转换为List<T> ,这似乎是你想要的。

The Where extension filters and returns IEnumerable<TSource> hence you need to call .ToList() to convert it back Where扩展过滤并返回IEnumerable<TSource>因此您需要调用.ToList()将其转换回来

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). IEnumerable和IList之间的区别在于,可枚举不包含任何数据,它包含一个迭代器 ,当您请求新数据时它会遍历数据(例如,使用foreach循环)。 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. 在您的情况下,要创建List,ToList()方法将遍历整个数据并将它们添加到List对象。

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. 例如,如果您计划多次使用整个数据,则应该使用该列表,但如果您计划使用它一次或计划使用linq再次查询,则应该选择enumerable。

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. 编辑:为什么返回类型Where WhereListIterator而不是List的问题的答案,部分是因为Linq如何工作。 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. 例如,如果您在第一个之后有另一个Where或另一个Linq语句,则编译器将使用整个方法链创建单个查询,然后返回最终查询的迭代器。 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. 另一方面,如果第一个Where将返回一个List,它将导致链中的每个Linq方法分别对数据执行。

Try this: 试试这个:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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