为什么不调用该方法?

San*_*eep 4 linq c#-4.0

只是想更好地理解这一点.我知道这是因为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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我使用它的地方.

List<int> list = new List<int>() { 1, 3, 4, 2, 8, 1 };

var s = list.Where(x => x > 4);

var result = s.ToList();
Run Code Online (Sandbox Code Playgroud)

我的问题是WhereIEnumerable上的静态方法为什么不在list.where()上调用它.但它在s.ToList()上调用.

我在Enumerable.Where()上有一个断点,它没有被击中s = list.Where(x => x > 4)但断点被击中s.ToList()

在我看到我的评论后,YUCK Why does LINQ have deferred execution?我将这个问题添加到了这个问题中.

请告诉我.

Ree*_*sey 7

Where实际调用该方法,但它返回一个IEnumerable<T>.此返回值实际上是编译器为您实现的类.

请注意,您的实现使用迭代器(它包括yield return ...).当这种情况发生时,编译器周围改变你的方法,以便它创建一个编译器生成的类,并且,你居然迭代通过IEnumerable<T>,你写的代码得到执行.

第一次MoveNext调用时,第一次yield return执行代码将被执行.第二次通话将持续到下一次,等等.

调用ToList()整个枚举IEnumerable<T>,然后执行整个方法.

此外 - ToList()此处不需要执行您的代码.你可以使用foreach循环:

foreach(var val in s) 
{
     // Do something...
}
Run Code Online (Sandbox Code Playgroud)

甚至可以手动执行调用:

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();
}
Run Code Online (Sandbox Code Playgroud)