2010-12-15 14 views
6

bien, ya que estaba hurgando con la construcción de un empadronador costumbre, habían notado este comportamiento que se refiere al rendimiento Las maravillas de la palabra clave de rendimiento

Digamos que tiene algo como esto:

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

    } 

¿Qué hace posible debajo del capó del compilador ejecutar el índice ++ y el resto del código en el ciclo while después de que técnicamente se recupera de la función?

Respuesta

9

El compilador reescribe el código en una máquina de estados. El único método que escribió está dividido en diferentes partes. Cada vez que llamas al MoveNext (implícita o explícitamente), el estado avanza y se ejecuta el bloque de código correcto.

Lecturas recomendadas si desea conocer más detalles:

+0

Sí, vale, máquina de estados, eso es lo que leo. ¿Pero qué tipo de código genera y qué hace esa máquina de estado con él? Pseudo código sería muy apreciado. – dexter

+0

@ Max Malygin: el artículo que he vinculado a http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx muestra el código que se genera. –

+0

@Mark, genial, gracias, los revisaré. – dexter

2

El rendimiento es magia.

Bueno, realmente no. El compilador genera una clase completa para generar la enumeración que estás haciendo. Básicamente es azúcar para simplificar tu vida.

Lea this para una introducción.

EDITAR: Wrong this. El enlace cambió, verifica de nuevo si tienes una vez.

+0

gracias, esto ayuda un poco, entonces + – dexter

+0

@Max - Dependiendo de cuando hizo clic en el enlace, puede ser diferente ahora. Originalmente publiqué el equivocado. – Donnie

4

El compilador genera una máquina de estado en su nombre.

De la especificación del lenguaje: Objetos

10.14 iteradores

10.14.4 Enumerador

Cuando un miembro de función que devuelve un tipo de interfaz empadronador es implementarse usando un bloque de iterador, invocando el miembro de función no ejecute inmediatamente el código en el bloque iterador. En su lugar, se crea y devuelve un objeto enumerador . Este objeto encapsula el código especificado en el bloque de iteradores, y la ejecución del código en el bloque iterador se produce cuando se invoca el método MoveNext del objeto enumerador.Un objeto empadronador tiene las siguientes características:

• Implementa IEnumerator y IEnumerator, donde T es el tipo de rendimiento del iterador.

• Implementa System.IDisposable.

• Se inicializa con una copia de los valores de argumento (si hay alguno) y el valor de instancia pasado al miembro de la función.

• Tiene cuatro estados potenciales, antes, en ejecución, suspendido y después, y está inicialmente en el estado anterior.

Un objeto empadronador es típicamente un instancia de una clase empadronador generado por el compilador que encapsula el código en el bloque iterador y implementa las interfaces empadronador, pero otros métodos de aplicación son posibles. Si una clase de enumerador es generado por el compilador, se anida esa clase , directa o indirectamente, en la clase que contiene el miembro de función, que tendrá accesibilidad privada, y se haber un nombre reservado para el uso del compilador (§2.4.2).

Para tener una idea de esto, así es como reflector decompiles su clase:

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 Me perdí la parte 4 :-(¡Bien visto! –

Cuestiones relacionadas