2012-01-24 4 views
13

¿En qué se compila C# lambda? ¿Un marco de pila, una instancia de tipo anónimo o?¿En qué se compila C# lambda? ¿Un marco de pila, una instancia de tipo anónimo o?

He leído esto question. Que en su mayoría responde "por qué" no se puede usar una lambda cuando también se utilizan funciones de tipo implícito. Pero, esta pregunta tiene como objetivo responder qué constructo produce el compilador para realmente llevar a cabo el código de una lambda. ¿Es una llamada a un método de tipo anónimo (algo así como tipos anónimos que implementan una interfaz en Java?) O es solo un marco de pila con referencias a variables cerradas y la aceptación de la firma del parámetro? Algunos lambda no se cierran sobre nada, entonces hay 2 resultados diferentes de la compilación.

+2

En realidad, hay dos implementaciones completamente diferentes: ¿es un delegado? ¿O un árbol de expresión? –

+0

Probablemente un árbol de expresiones es lo que busco aquí: (x) => x.ToString() algo así. Supongo que un delegado es en realidad una instancia de un tipo debido a + = y lo que no. – lucidquiet

+1

@lucidquier la sintaxis es idéntica; usted no puede decir lo que es a menos que sepa el tipo de asignación o tipo de parámetro. –

Respuesta

15

Suponiendo que quiere decir "como delegado", entonces todavía depende: p si captura cualquier variable (incluyendo "este", que puede estar implícito), entonces esas variables son en realidad implementados como campos en un tipo generado por el compilador (no expuesto en ningún lugar público), y el cuerpo de la declaración se convierte en un método en esa clase de captura. Si hay múltiples niveles de captura, la captura externa es nuevamente un campo en la clase de captura interna. Pero esencialmente:

int i = ... 
Func<int,int> func = x => 2*x*i; 

Es como;

var capture = new SecretType(); 
capture.i = ... 
Func<int,int> func = capture.SecretMethod; 

Donde:

class SecretType { 
    public int i; 
    public int SecretMethod(int x) { return 2*x*i; } 
} 

Esto es idéntico a "métodos anónimos", pero con diferente sintaxis.

Tenga en cuenta que los métodos que no capturan el estado pueden implementarse como métodos estáticos sin una clase de captura.

árboles de expresión, por otro lado ... son más difíciles de explicar: p

Pero (no tengo un compilador a mano, así que tengan paciencia conmigo):

int i = ... 
Expression<Func<int,int>> func = x => 2*x*i; 

Es algo así como:

var capture = new SecretType(); 
capture.i = ... 
var p = Expression.Parameter("x", typeof(int)); 
Expression<Func<int,int>> func = Expression.Lambda<Func<int,int>>(
    Expression.Multiply(
     Expression.Multiply(Expression.Constant(2),p), 
     Expression.PropertyOrField(Expression.Constant(capture), "i") 
    ), p); 

(excepto el uso de la inexistente "memberof" construir, ya que el compilador puede engañar)

Los árboles de expresión son complejos, pero se pueden deconstruir e inspeccionar, por ejemplo, para traducir a TSQL.

1

Las expresiones Lambda son de hecho funciones anónimas, pero con más versatilidad. Estos dos artículos creados por MSDN tienen mucha información sobre las expresiones lambda, cómo usarlas, qué precedencia tiene el operador =>, cuál es su relación con las funciones anónimas y algunas sugerencias de uso avanzadas.

Lambda Expressions (MSDN)

=> Operator (MSDN)

1

Éstos son algunos ejemplos:

public class C 
{ 
    private int field = 0; 

    public void M() 
    { 
     int local = 0; 

     Func<int> f1 =() => 0; 
     // f1 is a delegate that references a compiler-generated static method in C 

     Func<int> f2 =() => this.field; 
     // f2 is a delegate that references a compiler-generated instance method in C 

     Func<int> f3 =() => local; 
     // f3 is a delegate that references an instance method of a compiler-generated nested class in C 
    } 
} 
1

Una expresión lambda es un método sin nombre escrito en lugar de istance delegado. El compilador convierte a cualquiera:

  • Un ejemplo delegado
  • un árbol de expresión , de tipo Expression<TDelegate> que representa el código en el interior, en un modelo de objeto desplazable. Esto permite que la expresión lambda se interprete en tiempo de ejecución.

El compilador resuelve las expresiones lambda moviendo el código de la expresión a un método privado.

Cuestiones relacionadas