2016-05-31 3 views
22

私はyieldIEnumerableの周りいじるたとするか、次のスニペットがどのように動作するか、なぜ私が今興味:IEnumerator<int>収量はどのようにして列挙可能ですか?

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

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

が今どのようにコンパイラがこれをオンにしますか?

+3

http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx –

+1

コンパイラの魔法! – RBarryYoung

答えて

27

yield returnを使用すると、コンパイラは列挙子クラスを生成します。したがって、実際に使用されるコードは、2つの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クラスを参照していますか?これはあなたの2つのyield returnに基づいて生成されます。

12

コンパイラがyield returnまたはyield breakと表示されたとき、関数を受け取り、それをステートマシンを実装するクラスに変換します。メソッドが呼び出されると、このクラスのインスタンスが返されます。

C# In Depthには、コードの外観のセクションがあります。

5

これは発電機です。 私はcompilatorの背後にどのように動作するかを言うことはできませんが、やるとき:

yield return x; 

あなたが代わりにあなたが値を返すと、関数の実行を継続する、古典的なリターンのような機能を残すことはありません。

私がよく覚えているのは、実際の列挙型とこれとの間に少し違いがあります。ジェネレータを真の列挙型に変換するメソッドを使用しないと(実行しようとするものに応じて)いくつかの問題があります。

+0

違いを広げることができますか?コンパイラが列挙可能な実装を生成することを他の人が指摘しているので、 – Mafii

+0

私はそれを見つけようとします。 –

+0

あなたは何かを見つけましたか? – Mafii

関連する問題