yield 是如何实现延迟加载的模式的? [英] How yield implements the pattern of lazy loading?

查看:21
本文介绍了yield 是如何实现延迟加载的模式的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

yield如何实现延迟加载的模式?

推荐答案

yield 实现只有在需要时才会到达代码.

yield implementation doesn't reach the code until it's needed.

例如这段代码:

public IEnumerable<int> GetInts()
{
    yield return 1;
    yield return 2;
    yield return 3;
}

实际上会编译成一个实现 IEnumerable 的嵌套类,GetInts() 的主体将返回该类的一个实例.

Will actually compile into a nested class which implements IEnumerable<int> and the body of GetInts() will return an instance of that class.

使用反射器可以看到:

public IEnumerable<int> GetInts()
{
    <GetInts>d__6d d__d = new <GetInts>d__6d(-2);
    d__d.<>4__this = this;
    return d__d;
}

编辑 - 添加有关 GetInts 实现的更多信息:
此实现使其惰性的方式基于 Enumerator MoveNext() 方法.当生成可枚举嵌套类时(示例中的 d__6d),它有一个状态,并且每个状态都有一个值连接(这是一个简单的情况,在更高级的情况下,值将在代码到达状态时进行评估).如果我们查看 <GetInts>d__6dMoveNext() 代码,我们将看到状态:

Edit - adding more info about GetInts implementation:
The way this implementation makes it lazy is based on the Enumerator MoveNext() method. When the enumerable nested class is generated (<GetInts>d__6d in the example), it has a state and to each state a value is connected (this is a simple case, in more advanced cases the value will be evaluated when the code reach the state). If we take a look in the MoveNext() code of <GetInts>d__6d we'll see the state:

private bool MoveNext()
{
    switch (this.<>1__state)
    {
        case 0:
            this.<>1__state = -1;
            this.<>2__current = 1;
            this.<>1__state = 1;
            return true;

        case 1:
            this.<>1__state = -1;
            this.<>2__current = 2;
            this.<>1__state = 2;
            return true;

        case 2:
            this.<>1__state = -1;
            this.<>2__current = 3;
            this.<>1__state = 3;
            return true;

        case 3:
            this.<>1__state = -1;
            break;
    }
    return false;
}

当枚举器被要求提供当前对象时,它返回连接到当前状态的对象.

When the enumerator is asked for the current object it returns the object which is connected to the current state.

为了表明代码仅在需要时才进行评估,您可以查看此示例:

In order to show that the code is evaluated only when it's required you can look at this example:

[TestFixture]
public class YieldExample
{
    private int flag = 0;
    public IEnumerable<int> GetInts()
    {
        yield return 1;
        flag = 1;
        yield return 2;
        flag = 2;
        yield return 3;
        flag = 3;
    }

    [Test]
    public void Test()
    {
        int expectedFlag = 0;
        foreach (var i in GetInts())
        {
            Assert.That(flag, Is.EqualTo(expectedFlag));
            expectedFlag++;
        }

        Assert.That(flag, Is.EqualTo(expectedFlag));
    }
}

我希望它更清楚一点.我建议使用 Reflector 查看代码,并在更改yield"代码时观察编译后的代码.

I hope it's a bit more clear. I recommend to take a look at the code with Reflector and observe the compiled code as you change the "yield" code.

这篇关于yield 是如何实现延迟加载的模式的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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