Avertissement: Ma réponse décrit en fait capturé variables qui est différent de celui lambda de levage. Mal lu la question (besoin de sommeil). Mais j'ai passé un peu de temps à écrire ce donc je suis réticent à le supprimer. À gauche comme un WIKI de la communauté.
Lambda de levage, souvent désigné comme les fermetures, est une façon de façon transparente permettant l'accès de la portée des variables à partir de l'intérieur d'un ensemble d'expressions lambda.
Il est difficile d'entrer dans les détails concrets de fermetures sans choisir une langue en particulier. L'un des effets secondaires de lambda de levage, en toutes langues, c'est qu'il a tendance à prolonger la durée de vie d'une variable à partir d'un local à durée de vie courte portée, beaucoup plus vécu portée. Habituellement, cela se produit sous la forme d'un transfert d'une variable de la pile sur le tas dans le compilateur. C'est une langue très spécifique de l'action et, par conséquent, produit de très différentes implémentations basées sur la langue.
Je vais me concentrer sur C# car c'est probablement la langue la plus commune pour les lecteurs de débordement de la pile. Permet de commencer avec le code suivant.
public Func<int> GetAFunction() {
var x = 42;
Func<int> lambda1 = () => x;
Func<int> lambda2 = () => 42;
...
return lambda1;
}
Dans cet exemple, nous avons créé 2 les expressions lambda. Dans les deux cas, il est attribué à un représentant de l'instance de type Func. Tous les délégués .Net exiger qu'une fonction réelle de sauvegarde quelque part. Sous le capot, toutes les expressions lambda/ fonctions anonymes en C# sont traduites dans une définition de la méthode.
La génération d'une fonction pour lambda2 est assez simple. C'est un cas isolé fonction qui retourne une valeur constante.
public static int RealLambda2() {
return 42;
}
Générer lambda1 est un peu plus difficile. Une définition littérale serait la suivante
public static int RealLambda1() {
return x;
}
De toute évidence, cela ne compile pas parce que x n'est pas accessible. Afin de rendre ce travail, le compilateur C# doit soulever la variable x dans une clôture. Il peut alors retourner un pointeur vers une fonction à l'intérieur de la fermeture à satisfaire le délégué de l'expression
class Closure1 {
int x;
public int RealLambda1() {
return x;
}
}
C'est un exemple assez simple, mais devrait, espérons-le détail de l'art de levage. Le diable est malheureusement dans les détails et devient beaucoup plus complexe avec le scénario.