为何IEnumerables上的标准扩展方法

时间:2011-11-16 07:47:33

标签: c# visual-studio linq extension-methods

当我在列表上使用标准的扩展方法时,例如 哪里(...)

结果总是 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(...)

4 个答案:

答案 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)

您无法将asIEnumerable<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);
    }
}