代码之家  ›  专栏  ›  技术社区  ›  geostocker

C#[重复]中的产量理解困难

  •  15
  • geostocker  · 技术社区  · 8 年前

    我希望对我最近在调试器中遇到的一个片段进行一些澄清,但我确实无法理解。

    我正在接受 现在的话题是 yield 并返回一个 IEnumerable<T> 使用关键字。

    我有一个非常基本的函数,返回一个 IEnumerable Vendors (一个简单的类 Id , CompanyName Email

    public IEnumerable<Vendor> RetrieveWithIterator()
    {
        this.Retrieve(); // <-- I've got a breakpoint here
        foreach(var vendor in _vendors)
        {
            Debug.WriteLine($"Vendor Id: {vendor.VendorId}");
            yield return vendor;
        }
    }
    

    var vendorIterator = repository.RetrieveWithIterator(); // <-- Why don't it enter function?
    foreach (var item in vendorIterator) // <-- But starts here?
    {
        Debug.WriteLine(item);
    }
    var actual = vendorIterator.ToList();
    

    RetrieveWithIterator IEnumerable可数 收藏(见评论)。

    3 回复  |  直到 8 年前
        1
  •  16
  •   InBetween    8 年前

    这被称为延迟执行, yield 懒惰,只会根据需要工作。

    这有很多优点,其中之一是可以创建看似无限的枚举:

    public IEnumerable<int> InfiniteOnes()
    {
         while (true)
             yield 1;
    }
    

    现在想象一下:

    var infiniteOnes = InfiniteOnes();
    

    你会有一个 StackOverflow

    另一方面,由于其懒惰,您可以执行以下操作:

    var infiniteOnes = InfiniteOnes();
    //.... some code
    foreach (var one in infiniteOnes.Take(100)) { ... }
    

    后来,

    foreach (var one in infiniteOnes.Take(10000)) { ... }
    

    迭代器块仅在需要时运行;当枚举被迭代时,不是在之前,也不是在之后。

        2
  •  5
  •   aloisdg    8 年前

    推迟执行

    延迟执行意味着表达式的计算被延迟,直到实际需要其实现值。当您必须操作大型数据集合时,延迟执行可以极大地提高性能,尤其是在包含一系列链式查询或操作的程序中。在最好的情况下,延迟执行只允许通过源集合进行单个迭代。

    当在迭代器块中使用时,C语言中的yield关键字(以yield return语句的形式)直接支持延迟执行。这样的迭代器必须返回类型为的集合 IEnumerator IEnumerator<T> (或派生类型)。

    var vendorIterator = repository.RetrieveWithIterator(); // <-- Lets deferred the execution
    foreach (var item in vendorIterator) // <-- execute it because we need it
    {
        Debug.WriteLine(item);
    }
    var actual = vendorIterator.ToList();
    

    当您编写一个实现延迟执行的方法时,您还必须决定是使用延迟求值还是使用即时求值来实现该方法。

    延迟评估通常会产生更好的性能,因为它在整个集合评估过程中均匀分布开销处理,并最大限度地减少临时数据的使用。当然,对于某些操作,除了实现中间结果之外,别无选择。

    source

        3
  •  2
  •   EpicKip    8 年前

    当你需要时,它会在上面循环时得到这些项目。这样说,你只需要前4个结果,然后你打破了,它不会产生任何更多,你只是节省了一些处理能力!

    MS Docs

    使用yield-return语句一次返回一个元素。 您可以使用yield-break语句来结束迭代。

    -如果你 .ToList() 对于生成的方法的结果,它将像返回单个列表一样工作,从而破坏了生成的目的。