产量如何可数?

时间:2016-05-31 08:16:31

标签: c# ienumerable yield-return

我正在使用yieldIEnumerable,我现在很好奇以下代码段的工作原理或方式:

public class FakeList : IEnumerable<int>
{
    private int one;
    private int two;

    public IEnumerator<int> GetEnumerator()
    {
        yield return one;
        yield return two;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

现在编译器如何转变:

public IEnumerator<int> GetEnumerator()
{
    yield return one;
    yield return two;
}

加入IEnumerator<int>

3 个答案:

答案 0 :(得分:27)

使用yield return时,编译器会为您生成枚举器类。因此,使用的实际代码比仅仅两个返回语句复杂得多。编译器添加所有必要的代码以返回枚举器,迭代来自yield return的结果。

这是您FakeList.GetEnumerator()生成的代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;

public class FakeList : IEnumerable<int>, IEnumerable
{
    private int one;
    private int two;

    [IteratorStateMachine(typeof(<GetEnumerator>d__2))]
    public IEnumerator<int> GetEnumerator()
    {
        yield return this.one;
        yield return this.two;
    }

    IEnumerator IEnumerable.GetEnumerator() => 
        this.GetEnumerator();

    [CompilerGenerated]
    private sealed class <GetEnumerator>d__2 : IEnumerator<int>, IDisposable, IEnumerator
    {
        private int <>1__state;
        private int <>2__current;
        public FakeList <>4__this;

        [DebuggerHidden]
        public <GetEnumerator>d__2(int <>1__state)
        {
            this.<>1__state = <>1__state;
        }

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

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

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

        [DebuggerHidden]
        void IEnumerator.Reset()
        {
            throw new NotSupportedException();
        }

        [DebuggerHidden]
        void IDisposable.Dispose()
        {
        }

        int IEnumerator<int>.Current =>
            this.<>2__current;

        object IEnumerator.Current =>
            this.<>2__current;
    }
}

你看到<GetEnumerator>d__2班了吗?这是根据您的两个yield return生成的。

答案 1 :(得分:12)

当编译器看到yield returnyield break时,它会接受该函数并将逻辑转换为实现状态机的类。调用该方法后,将返回此类的实例。

C# In Depth有一段关于代码的内容。

答案 2 :(得分:5)

这是一个发电机。 我不能说compilator是如何工作的,但是当你这样做时:

yield return x;

您不会像经典返回一样离开函数,而是返回一个值,然后继续执行该函数。

如果我记得很清楚,真正的可枚举和这个之间有一点区别,如果你不使用一种方法将你的生成器转换为真正的可枚举(取决于你想要完成的东西),你可以拥有一些麻烦。