2016-05-31 17 views
22

Ben yield ve IEnumerable etrafında oyun oynuyordu ve ya aşağıdaki pasajı nasıl çalıştığını neden şimdi merak ediyorum: Bir IEnumerator<int> içineVerim nasıl sayılır?

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

Şimdi nasıl derleyici bu tahrik mi ediyor?

+3

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

+1

derleyici sihir! – RBarryYoung

cevap

27

yield return kullanırken, derleyici sizin için bir numaralandırma sınıfı oluşturur. Yani kullanılan gerçek kod, sadece iki dönüş ifadesinden çok daha karmaşıktır. Derleyici, sizin için bir numaralayıcı döndürmek için gerekli tüm kodu ekler, bu da yield return sonuçlarından yinelenir.


Bu FakeList.GetEnumerator() üretilen kod edilir:

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

Eğer <GetEnumerator>d__2 sınıfı görüyor musunuz? Bu, iki yield return s'ye bağlı olarak oluşturulur.

12

Derleyici, yield return veya yield break'u gördüğü zaman işlevi alır ve mantığı, bir durum makinesini uygulayan bir sınıfa kapsamaz. Bu sınıfın bir örneği, yöntem çağrıldığında döndürülür. Kodun neye benzediğine dair bir bölüm var.

C# In Depth.

5

Bu bir jeneratördür. Ben compilator arkasında nasıl çalıştığını söyleyemeyiz, ancak bunu yaparken:

yield return x; 

yerine Bir değer dönecektir, klasik dönüş gibi işlev terk edip ardından fonksiyonunun yürütülmesine devam etmeyecektir.

Eğer iyi hatırlarsam, gerçek numaralandırılabilir ile bu arasında bir fark vardır, eğer jeneratörünüzü gerçek sayılabilir bir değere dönüştürmek için bir yöntem kullanmazsanız (ne yapmaya çalıştığınıza bağlı olarak) bazı sıkıntılarınız var.

+0

Farkı genişletebilir misiniz? Diğerleri derleyici sayısız bir uygulama – Mafii

+0

oluşturmak için menton olduğunu çünkü onu bulmaya çalışacağız. –

+0

Bir şey buldunuz mu? – Mafii