【问题标题】:How is yield an enumerable?产量如何是可枚举的?
【发布时间】:2016-05-31 08:16:31
【问题描述】:

我一直在玩 yieldIEnumerable,现在我很好奇以下 sn-p 为什么或如何工作:

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&lt;int&gt;?

【问题讨论】:

标签: c# ienumerable yield-return


【解决方案1】:

当使用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;
    }
}

你看到&lt;GetEnumerator&gt;d__2 类了吗?这是根据您的两个yield returns 生成的。

【讨论】:

    【解决方案2】:

    当编译器看到yield returnyield break 时,它会获取函数并将其逻辑转换为实现状态机的类。然后在调用该方法时返回该类的一个实例。

    C# In Depth 有一节介绍代码的外观。

    【讨论】:

      【解决方案3】:

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

      yield return x;
      

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

      如果我没记错的话,真正的可枚举和这个之间有一点区别,如果您不使用一种方法将您的生成器转换为真正的可枚举(取决于您要完成的工作),您可以拥有一些麻烦。

      【讨论】:

      • 您能详细说明差异吗?因为其他人都在暗示编译器会生成一个可枚举的实现
      • 我会努力找回来的。
      • 你找到什么了吗?
      • 我没有成功找回我遇到问题的案例。但凭记忆,这是一个参考问题。我无法在我的可枚举生成中枚举两次。但是当我做测试时,它很好。我还有一件事要尝试,它是使用扩展方法,行为可能会有所不同。
      • 我真的找不到了。因为,我修复了它,我没有代码可以记住我是如何做到的。
      猜你喜欢
      • 1970-01-01
      • 2013-05-18
      • 2020-11-17
      • 2014-09-20
      • 1970-01-01
      • 2021-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多