繁体   English   中英

Linq 中的 Take(x) 是否在获取 x 个对象时停止枚举?

[英]Does Take(x) in Linq stops enumerating when taking x objects?

例如,如果我有以下代码:

    public static void Main(string[] args)
    {
        List<int> list = new List<int>() { 2, 3, 2, 9, 10, 2, 5 };

        var out = list.Where(x => x == 2).Take(2).ToList();
    }

迭代次数是 3(因为后两个在索引 2 中)还是 7(元素总数)?

谢谢

是的,停止。

你可以通过如下重写代码清楚地看到这一点:

var result = list.Where(x =>
    {
        Console.WriteLine("Where: " + x);
        return x == 2;
    })
    .Take(2).ToList();

list将由Where function 迭代,仅返回匹配项。
Where将被Take迭代,在 2 个结果后停止。
Take完全由ToList迭代

所以最终的结果是list的迭代在2的第二项被Take停止了。

您可以自己轻松检查。 让我们测试一下达到9的假设(即至少迭代了4 个项目):

var result = list
  .Where(x => x == 2)        // your query under test
  .Take(2)
  .Select(item => item != 9  // business as usual for the first 3 items
     ? item                  // throw exception on the 4th
     : throw new Exception("Strange execution: 9 (4th item) has been scanned"))
  .ToList();                 // materialization executes the query

运行它,你会看到第 4 项( 9 )没有被取走:没有抛出异常。

我认为最有说服力(也是最简单)的答案是查看TakeIterator在调用Take时运行的源代码

static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> source, int count) 
{
    if (count > 0) {
        foreach (TSource element in source) {
            yield return element;
            if (--count == 0) break; // Yep, it stops after "count" iterations
        }
    }
}

如果你用自己的 IEnumerable 和 IEnumerator 编写一些测试代码,就很容易看出会发生什么。

class MyCollection : IEnumerable<int>
{
    public List<int> Data {get; set;} = new List<int>() { 2, 3, 2, 9, 10, 2, 5 };

    public IEnumerator<int> GetEnumerator()
    {
         return new MyEnumerator()
         {
             Data = this.Data,
         };
    }
}

和枚举器:

class MyEnumerator : IEnumerator<int>
{
    private int index = -1;
    public List<int> Data {get; set;}

    public void Reset()
    {
        this.index = -1;
    }

    public bool MoveNext()
    {
        ++this.index;
        return this.index < this.Data.Count;
    }

    public int Current
    {
        get
        {
            int returnValue = this.Data[this.index];
            Debug.WriteLine("[{0}] {1}", this.index, returnValue);
            return returnValue;
        }
    }
}

测试代码:

void Main()
{
    MyCollection collection = new MyCollection();
    var out = collection.Where(x => x == 2).Take(2).ToList();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM