如何转换此迭代器阻止功能更改?

Ser*_*rvy -22 c# iterator yield-return deferred-execution

给出以下代码段:

public class Foo
{
    public IEnumerable<string> Sequence { get; set; }
    public IEnumerable<string> Bar()
    {
        foreach (string s in Sequence)
            yield return s;
    }
}
Run Code Online (Sandbox Code Playgroud)

以下代码片段在语义上是等价的,还是不同?如果不同,它们的功能如何不同?

public class Foo2
{
    public IEnumerable<string> Sequence { get; set; }
    public IEnumerable<string> Bar2()
    {
        return Sequence;
    }
}
Run Code Online (Sandbox Code Playgroud)

这个问题的灵感来自于这个问题,它提出了一个类似情况的不同问题.

Ser*_*rvy 24

这两者并不相同.两种Bar方法之间如何延迟执行的语义是不同的. 当你打电话时Foo.Bar会评估Sequence成一个IEnumerable值. 当您枚举返回的序列时,将评估该变量中的值.BarFoo2.Bar2SequenceBar2

我们可以编写一个足够简单的程序来观察这里的差异.

//Using iterator block
var foo = new Foo();
foo.Sequence = new[] { "Old" };
var query = foo.Bar();
foo.Sequence = new[] { "New" };
Console.WriteLine(string.Join(" ", query));

//Not using iterator block
var foo2 = new Foo2();
foo2.Sequence = new[] { "Old" };
var query2 = foo2.Bar2();
foo2.Sequence = new[] { "New" };
Console.WriteLine(string.Join(" ", query2));
Run Code Online (Sandbox Code Playgroud)

打印出:


在这种特殊情况下,我们的Bar方法也没有副作用.如果确实如此,那么了解程序所具有的语义以及应该具有的语义就不那么重要了.例如,让我们修改这两个方法,使它们有一些可观察到的副作用:

public class Foo
{
    public IEnumerable<string> Sequence { get; set; }
    public IEnumerable<string> IteratorBlock()
    {
        Console.WriteLine("I'm iterating Sequence in an iterator block");
        foreach (string s in Sequence)
            yield return s;
    }
    public IEnumerable<string> NoIteratorBlock()
    {
        Console.WriteLine("I'm iterating Sequence without an iterator block");
        return Sequence;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在让我们尝试比较这两种方法,看看它们是如何运作的:

var query = foo.IteratorBlock();
var query2 = foo.NoIteratorBlock();
Console.WriteLine("---");
query.Count();
query.Count();
query2.Count();
query2.Count();
Run Code Online (Sandbox Code Playgroud)

这将打印出来:

我在没有迭代器块的情况下迭代Sequence
---
我在迭代器块中
迭代Sequence我在迭代器块中迭代Sequence

在这里我们可以看到非迭代器块的副作用在调用方法本身时发生,并且迭代器块的副作用在那个时间点不会发生.然后,稍后,每次迭代非迭代器块时它根本不会产生副作用,但迭代器块会在每次迭代查询时产生副作用.

  • 恭喜,截至[上周](https://stackoverflow.com/help/badges/95/reversal?userid=1159478),您现在是[两个]之一的自豪持有者(http:// data. stackexchange.com/stackoverflow/query/677715/self-answered-reversals)自我回答整个网络上的逆转徽章. (16认同)
  • @quantumpotato他并不粗鲁,只是指出他们认为有趣的东西(我也发现了幽默).另请注意,我同时发布了问题和答案; 在我写这个问题之前,我知道答案.我只是写了它,因为其他人表现出对它的误解(在链接的问题中)所以我发布这个问题来保持对这个主题的解释(这个问题不在主题上),而不会分散实际被问到的问题. (4认同)
  • 试图理解投票的逻辑确实很有趣。他们似乎在说,做得好,答题者,因为如此清晰地回答了这个愚蠢的问题。您显然比那个愚蠢的提问者聪明得多。 (2认同)