为什么IEnumerable.ToList()在以下情况下不起作用:
var _listReleases= new List<string>;
_listReleases.Add("C#")
_listReleases.Add("Javascript");
_listReleases.Add("Python");
IEnumerable sortedItems = _listReleases.OrderBy(x => x);
_listReleases.Clear();
_listReleases.AddRange(sortedItems); // won't work
_listReleases.AddRange(sortedItems.ToList()); // won't work
答案 0 :(得分:2)
LINQ被懒惰地评估了。当你运行这一行时:
IEnumerable sortedItems = _listReleases.OrderBy(x => x);
你实际上并没有正确地订购物品。相反,您正在构建一个枚举,当枚举时,它将按顺序返回_listReleases
中当前的对象。因此,当您Clear()
列表时,它不再有任何要订购的商品。
您需要强制它在之前评估,以清除_listReleases
。一种简单的方法是添加ToList()
电话。此外,与AddRange
不兼容的IEnumerable
类型也不会接受它。您可以使用var
隐式地将其键入List<string>
,这将起作用,因为List<T> : IEnumerable<T>
(它实现了接口)。
var sortedItems = _listReleases.OrderBy(x => x).ToList();
_listReleases.Clear();
_listReleases.AddRange(sortedItems);
您还应该注意,ToList()
等方法是IEnumerable<T>
的扩展方法,而不是IEnumerable
,因此((IEnumerable)something).ToList()
不起作用。与Java不同,Something<T>
和Something
在C#中是完全不同的类型。
答案 1 :(得分:2)
由于这一行不起作用:
_listReleases.Clear();
首先,_listReleases此时不为null。它只是空,这是完全不同的事情。
但要解释为什么这不能按预期工作:IEnumerable
接口类型不实际上为任何事物分配或保留存储空间。它表示可以与foreach
循环一起使用的对象,仅此而已。它实际上不需要将项目存储在集合中。
有时,IEnumerable引用确实将这些项目放在同一个对象中,但它不必。这就是这里发生的事情。 OrderBy()
扩展方法仅创建一个对象,该对象知道如何查看原始列表并按特定顺序返回项目。但是这些物品没有存储空间。它仍然取决于它的原始数据源。
此情况的最佳解决方案是此时停止使用_listReleases
变量,而只使用sortedItems
变量。只要前者不是收集的,后者就会做你需要的。但是如果你真的想要_listReleases
变量,你可以这样做:
_listReleases = sortedItems.ToList();
现在回到IEnumerables。这个属性有一些很好的好处,不需要立即存储项目本身,只是抽象了迭代集合的能力: