理解yield关键字和LINQ

时间:2012-03-01 11:12:04

标签: c# .net linq

我正在尝试更好地理解yield关键字,我认为我对它有足够的理解,所以我进行了一些测试,但是我对结果感到惊讶。

如果我运行下面的代码,我得到以下输出,表明它在整个范围内循环,而不仅仅是4号。

    public void DoIt()
    {
        Console.WriteLine("Method Call");
        var results = GetData(Enumerable.Range(1, 10));
        Console.WriteLine("LINQ");
        var filtered = results.Where(x => x == 4);
        Console.WriteLine("Start result loop");
        foreach (var item in filtered)
        {
                Console.WriteLine("Item is " + item);
        }
    }

    private IEnumerable<int> GetData(IEnumerable<int> Input)
    {
        foreach (int item in Input)
        {
            if (item % 2 == 0)
            {
                Console.WriteLine("Found " + item);
                yield return item;
            }
        }
    }

输出:

Method Call
LINQ
Start result loop
Found 2
Found 4
Item is 4
Found 6
Found 8
Found 10

如果我运行以下代码,则表明它只会到达4然后停止。

    public void DoIt()
    {
        Console.WriteLine("Method Call");
        var results = GetData(Enumerable.Range(1, 10));
        Console.WriteLine("Start result loop");
        foreach (var item in results)
        {
            if (item == 4)
            {
                Console.WriteLine("Item is " + item);
                break;
            }
        }
    }

    private IEnumerable<int> GetData(IEnumerable<int> Input)
    {
        foreach (int item in Input)
        {
            if (item % 2 == 0)
            {
                Console.WriteLine("Found " + item);
                yield return item;
            }
        }
    }

输出:

Method Call
Start result loop
Found 2
Found 4
Item is 4

我想我并没有强调一些东西,但看起来LINQ正好与我的预期相反?我虽然LINQ也使用了yield和延迟执行,但我希望第二组代码的结果与第一组代码的结果相同。

2 个答案:

答案 0 :(得分:12)

它确实使用延迟执行。 LINQ Where检查输入可枚举的所有元素,当它到达找到的第一个元素时它不会停止。这就是First所做的。

如果您将Where更改为First,或者您从第二个示例中删除了break,那么您的第一个示例将返回与第二个示例相同的内容。

答案 1 :(得分:2)

我认为你的基本逻辑错了,而不是LINQ。你的第一个例子必须迭代整个范围,因为where-condition必须找到所有等于4的值,而不仅仅是第一个值,即等于4。