当我在列表上使用标准的扩展方法时,例如 哪里(...)
结果总是 IEnumerable ,以及何时 您决定执行列表操作,例如 Foreach()
我们需要投射(不漂亮)或使用 ToList()扩展方法
(也许)使用一个消耗更多内存的新List(是吗?):
List<string> myList=new List<string>(){//some data};
(编辑:此演员工作
)myList.Where(p=>p.Length>5).Tolist().Foreach(...);
或
(myList.Where(p=>p.Length>5) as List<string>).Foreach(...);
哪种代码更好?还是有第三种方式?
修改 Foreach是一个示例,将其替换为BinarySerach
myList.Where(p=>p.Length>5).Tolist().Binarysearch(...)
答案 0 :(得分:9)
as
绝对不是一个好方法,如果有效,我会感到惊讶。
就什么是“最佳”而言,我建议foreach
代替ForEach
:
foreach(var item in myList.Where(p=>p.Length>5)) {
... // do something with item
}
如果您绝望想要使用列表方法,可能是:
myList.FindAll(p=>p.Length>5).ForEach(...);
或确实
var result = myList.FindAll(p=>p.Length>5).BinarySearch(...);
但请注意,此 (与第一个不同)需要额外的数据副本,如果myList
中有100,000个项目长度超过5,则可能会很痛苦。< / p>
LINQ返回IEnumerable<T>
的原因是这个(LINQ-to-Objects)设计为可组合和流式传输,如果你去列表,不可能。例如,一些where
/ select
等的组合应该不严格需要创建大量的中间列表(事实上,LINQ没有)。
当你考虑到并非所有序列都有界时,这一点就更为重要;有无限序列,例如:
static IEnumerable<int> GetForever() {
while(true) yield return 42;
}
var thisWorks = GetForever().Take(10).ToList();
作为直到 ToList
组成迭代器,不生成中间列表。但是,有一些缓冲操作,如OrderBy
,需要先读取所有数据。大多数LINQ操作都是流式传输。
答案 1 :(得分:5)
design goals for LINQ中的一个是允许可组合查询在任何支持的数据类型上,这是通过使用泛型接口而不是具体类(例如{{)指定返回类型来实现的。 1}}正如你所指出的那样)。这允许根据需要实现螺母和螺栓,作为具体类(例如IEnumerable<T>
或提升到SQL查询中)或使用方便的WhereEnumerableIterator<T>
关键字。
另外,另一个design philosophy of LINQ is one of deferred execution。基本上,在您实际使用查询之前,没有做过任何实际工作。这允许可能仅在需要时完成可能昂贵的(or infinite as Mark notes)操作。
如果yield
返回另一个List<T>.Where
,它可能会限制合成,肯定会阻碍延迟执行(更不用说产生过多的内存)。
所以,回顾一下你的例子,使用List<T>
运算符结果的最佳方法取决于你想用它做什么!
Where
答案 2 :(得分:3)
如果你想在列表上做一个简单的foreach,你可以这样做:
foreach (var item in myList.Where([Where clause]))
{
// Do something with each item.
}
答案 3 :(得分:2)
您无法将as
)IEnumerable<string>
投射到List<string>
。 IEnumerable
在您访问项目时对项目进行评估。调用ToList<string>()
将枚举集合中的所有项并返回一个新的List,这是一个内存效率低下且不必要的。如果您愿意将ForEach
扩展方法用于任何集合,那么最好编写一个适用于任何集合的新ForEach
扩展方法。
public static void ForEach<T>(this IEnumerable<T> enumerableList, Action<T> action)
{
foreach(T item in enumerableList)
{
action(item);
}
}