如何转换此迭代器阻止功能更改? [英] How is transforming this iterator block a functional change?

查看:112
本文介绍了如何转换此迭代器阻止功能更改?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下代码片段:

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

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

is the following snippet semantically equivalent, or is it different? If it is different, how do they function differently?

public class Foo2
{
    public IEnumerable<string> Sequence { get; set; }
    public IEnumerable<string> Bar2()
    {
        return Sequence;
    }
}

此问题的灵感来自于这个问题,这是一个关于类似情况的另一个问题。

This question is inspired by this question which is asking a different question about a similar situation.

推荐答案

两者不相同。在两个 Bar 方法之间延迟执行的语义是不同的。 Foo.Bar 序列评估为 IEnumerable 当您致电 Bar 时。当您枚举<$返回的序列时, Foo2.Bar2 会将 Sequence 评估为该变量中的值c $ c> Bar2

The two are not equivalent. The semantics of how execution is deferred between the two Bar methods is different. Foo.Bar will evaluate Sequence into an IEnumerable value when you call Bar. Foo2.Bar2 will evaluate Sequence into the value in that variable when you enumerate the sequence returned by Bar2.

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

We can write a simple enough program to observe the differences here.

//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));

打印出来:


新增

New
Old

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

In this particular case our Bar method also has no side effects. If it did it would not be noticeably more important to understand the semantics that your program has, and what it should have. For example, let's modify the two methods so that they have some observable side effects:

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;
    }
}

现在让我们尝试比较这两种方法,看看它们是怎样的函数:

Now let's try comparing these two methods to see how they function:

var query = foo.IteratorBlock();
var query2 = foo.NoIteratorBlock();
Console.WriteLine("---");
query.Count();
query.Count();
query2.Count();
query2.Count();

这将打印出来:


我在没有迭代器块的情况下迭代序列

---

我在迭代器块中迭代序列

我在迭代器块中迭代序列

I'm iterating Sequence without an iterator block
---
I'm iterating Sequence in an iterator block
I'm iterating Sequence in an iterator block

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

Here we can see that the non-iterator block's side effects happen when the method itself is called, and the iterator block's side effects don't happen at that point in time. Then, later on, each time we iterate the non-iterator block it doesn't cause the side effects at all, but the iterator block causes the side effects each time the query is iterated.

这篇关于如何转换此迭代器阻止功能更改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆