为什么不调用该方法?

时间:2012-02-01 17:37:34

标签: 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;
            }
        }
    }
}

这是我使用它的地方。

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?的评论之后,我将其添加到问题中。

请告诉我。

3 个答案:

答案 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()的调用会执行迭代,从而导致执行过滤器。