2010-12-15 16 views
6

Ok, jak mi grzebać w budowaniu własnego wyliczający, Zauważyłem ten problem, który dotyczy Wydajność Cuda słowa kluczowego yield

że masz coś takiego:

public class EnumeratorExample 
    { 

     public static IEnumerable<int> GetSource(int startPoint) 
     { 
       int[] values = new int[]{1,2,3,4,5,6,7}; 
       Contract.Invariant(startPoint < values.Length); 
       bool keepSearching = true; 
       int index = startPoint; 

       while(keepSearching) 
       { 
         yield return values[index]; 
         //The mind reels here 
         index ++ 
         keepSearching = index < values.Length; 
       } 
     } 

    } 

Co umożliwia pod maską kompilatora wykonanie indeksu ++ i reszty kodu w pętli while po technicznym wykonaniu zwrotu z funkcji?

Odpowiedz

9

Kompilator przepisuje kod na automat stanów. Pojedyncza metoda, którą napisałeś, jest podzielona na różne części. Za każdym razem, gdy wywołujesz MoveNext (albo domyślnie, albo jawnie), stan jest zaawansowany i wykonywany jest poprawny blok kodu.

Sugerowana czytanie, jeśli chcesz poznać więcej szczegółów:

+0

Tak, ok, automat stanowy, to właśnie czytam. Ale jaki rodzaj kodu generuje i co robi ten automat państwowy? Pseudo kod byłby bardzo doceniany. – dexter

+0

@Max Malygin: Artykuł, który podłączyłem do http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx pokazuje wygenerowany kod. –

+0

@ Mark, cool, dzięki, będę sprawdzać te! – dexter

2

Wydajność jest magia.

Cóż, niezupełnie. Kompilator generuje pełną klasę, aby wygenerować wyliczenie, które robisz. To w zasadzie cukier, który uprości twoje życie.

Przeczytaj this w intro.

EDYCJA: Złe to. Link zmieniony, sprawdź ponownie, jeśli raz.

+0

dziękuję, to pomaga trochę, więc + – dexter

+0

@ Max - w zależności od tego, kiedy kliknąłeś na link, może być teraz inaczej. Pierwotnie wysłałem niewłaściwy. – Donnie

4

Kompilator generuje komputer stanu w Twoim imieniu.

od specyfikacji język:

10,14 Iterators

10.14.4 wyliczający obiektów

Gdy człon funkcję powrotu typu interfejsu numeratora jest realizowane za pomocą bloku iteracyjnej, Wywołanie funkcji członka nie powoduje natychmiastowego wykonania kodu blok iteratora. Zamiast tego zostanie utworzony i zwrócony obiekt modułu wyliczającego . Ten obiekt kapsułkuje kod podany w bloku iteratora, a wykonanie kodu w bloku iteratora występuje, gdy wywoływana jest metoda obiektu pobierającego o nazwie MoveNext. wyliczający obiekt ma następujące właściwości:

• to realizuje IEnumerator i IEnumerator , w którym T oznacza typ Wydajność iteracyjnej.

• Implementuje System.IDisposable.

• Jest inicjowany z kopią wartości argumentów (jeśli istnieje) i instancji wartość przekazana do elementu funkcji.

• Posiada cztery potencjalne stany, wcześniej, działa, zawieszone i po, i jest początkowo w stanie przed.

Przedmiotem wyliczający to typowo przykład kompilatora generowane klasy Enumerator kapsułkuje kod w bloku iteracyjnej i realizuje interfejsy Enumerator , ale możliwe są także inne sposoby implementacji . Jeśli klasa wyliczający jest generowany przez kompilator, że klasa zostaną zagnieżdżone bezpośrednio lub pośrednio, w klasie zawierającej element funkcyjny, będzie musiał prywatnej dostępności, a to będzie mieć nazwę zarezerwowana do użycia kompilatora (§2.4.2).

Aby zorientować się w tym, oto jak reflektor decompiles swoją klasę:

public class EnumeratorExample 
{ 
    // Methods 
    public static IEnumerable<int> GetSource(int startPoint) 
    { 
     return new <GetSource>d__0(-2) { <>3__startPoint = startPoint }; 
    } 

    // Nested Types 
    [CompilerGenerated] 
    private sealed class <GetSource>d__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable 
    { 
     // Fields 
     private int <>1__state; 
     private int <>2__current; 
     public int <>3__startPoint; 
     private int <>l__initialThreadId; 
     public int <index>5__3; 
     public bool <keepSearching>5__2; 
     public int[] <values>5__1; 
     public int startPoint; 

     // Methods 
     [DebuggerHidden] 
     public <GetSource>d__0(int <>1__state) 
     { 
      this.<>1__state = <>1__state; 
      this.<>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; 
     } 

     private bool MoveNext() 
     { 
      switch (this.<>1__state) 
      { 
       case 0: 
        this.<>1__state = -1; 
        this.<values>5__1 = new int[] { 1, 2, 3, 4, 5, 6, 7 }; 
        this.<keepSearching>5__2 = true; 
        this.<index>5__3 = this.startPoint; 
        while (this.<keepSearching>5__2) 
        { 
         this.<>2__current = this.<values>5__1[this.<index>5__3]; 
         this.<>1__state = 1; 
         return true; 
        Label_0073: 
         this.<>1__state = -1; 
         this.<index>5__3++; 
         this.<keepSearching>5__2 = this.<index>5__3 < this.<values>5__1.Length; 
        } 
        break; 

       case 1: 
        goto Label_0073; 
      } 
      return false; 
     } 

     [DebuggerHidden] 
     IEnumerator<int> IEnumerable<int>.GetEnumerator() 
     { 
      EnumeratorExample.<GetSource>d__0 d__; 
      if ((Thread.CurrentThread.ManagedThreadId == this.<>l__initialThreadId) && (this.<>1__state == -2)) 
      { 
       this.<>1__state = 0; 
       d__ = this; 
      } 
      else 
      { 
       d__ = new EnumeratorExample.<GetSource>d__0(0); 
      } 
      d__.startPoint = this.<>3__startPoint; 
      return d__; 
     } 

     [DebuggerHidden] 
     IEnumerator IEnumerable.GetEnumerator() 
     { 
      return this.System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator(); 
     } 

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

     void IDisposable.Dispose() 
     { 
     } 

     // Properties 
     int IEnumerator<int>.Current 
     { 
      [DebuggerHidden] 
      get 
      { 
       return this.<>2__current; 
      } 
     } 

     object IEnumerator.Current 
     { 
      [DebuggerHidden] 
      get 
      { 
       return this.<>2__current; 
      } 
     } 
    } 
} 
2
+0

+1 Tęskniłem za częścią 4 :-(Dobrze zauważony! –

Powiązane problemy