试着更好地理解这一点。我知道这是因为 Deffered Execution
但是什么导致该方法不会被立即调用。这是来自JonSkeet的EduLinq。
public static partial class Enumerable
{
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (predicate == null)
{
throw new ArgumentNullException("predicate");
}
foreach (TSource item in source)
{
if (predicate(item))
{
yield return item;
}
}
}
}
这是我使用它的地方。
List<int> list = new List<int>() { 1, 3, 4, 2, 8, 1 };
var s = list.Where(x => x > 4);
var result = s.ToList();
我的问题是虽然Where
是IEnumerable上的静态方法,但为什么它不会在list.where()上调用。但它在s.ToList()上调用。
我在Enumerable.Where()上有一个断点,它在s = list.Where(x => x > 4)
上没有被点击,但断点被点击s.ToList()
在我看到YUCK
Why does LINQ have deferred execution?
的评论之后,我将其添加到问题中。
请告诉我。
答案 0 :(得分:7)
实际调用Where
方法,但它返回IEnumerable<T>
。此返回值实际上是编译器为您实现的类。
请注意,您的实现使用迭代器(它包括yield return ...)。发生这种情况时,编译器会更改您的方法,以便创建编译器生成的类,并且,当您实际通过IEnumerable<T>
迭代时,会执行您编写的代码。
第一次调用MoveNext
时,第一个yield return
的代码将被执行。第二次通话将持续到下一次,等等。
调用ToList()
枚举整个IEnumerable<T>
,然后执行整个方法。
此外,此处不需要ToList()
来执行您的代码。你可以使用foreach循环:
foreach(var val in s)
{
// Do something...
}
甚至可以手动执行调用:
IEnumerable<int> s = list.Where(x => x > 4);
IEnumerator<int> sEnumerator = s.GetEnumerator(); // Get the enumerator
// This section will cause your code to run, but only until the *first* yield statement...
if (sEnumerator.MoveNext())
{
int val = sEnumerator.Current();
}
// Without further MoveNext() calls, you won't "finish" the foreach loop...
// This block will do one more "loop" in your foreach, going until the next "yield" (or the end of the method)
if (sEnumerator.MoveNext())
{
int val = sEnumerator.Current();
}
答案 1 :(得分:0)
LINQ使用延迟执行,当您实际请求数据时将调用该方法。
如果使用ToList(),则立即请求数据,从而立即枚举列表。
答案 2 :(得分:0)
你回答了自己的问题 - 因为延期执行(种类)。在被叫的地方,过滤本身就是推迟的。
List.Where不会返回已过滤的列表。它返回IEnumerable<int>
,迭代时 过滤列表。您对.ToList()
的调用会执行迭代,从而导致执行过滤器。