Dans quoi est compilé C # lambda? Un stackframe, une instance de type anonyme, ou?

Dans quoi est compilé C # lambda? Un stackframe, une instance de type anonyme, ou?

J’ai lu cette question . Ce qui répond le plus souvent au “pourquoi”, vous ne pouvez pas utiliser un lambda lorsque vous utilisez également des fonctionnalités de type implicite. Mais, cette question vise à répondre à la construction que le compilateur produit pour exécuter réellement le code d’un lambda. S’agit-il d’un appel à une méthode de type anonyme (comme des types anonymes implémentant une interface en Java?) Ou s’agit-il simplement d’un cadre de stack avec des références à des variables fermées et acceptant la signature de paramètre? Certains lambda ne ferment pas sur rien – il y a donc 2 sorties résultantes différentes de la compilation.

En supposant que vous vouliez dire “en tant que délégué”, cela dépend toujours: p s’il capture toutes les variables (y compris “this”, ce qui peut être implicite), ces variables sont en réalité implémentées comme des champs dans un type généré par le compilateur ), et le corps de l’instruction devient une méthode sur cette classe de capture. S’il existe plusieurs niveaux de capture, la capture externe est à nouveau un champ de la classe de capture interne. Mais essentiellement:

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

Est comme;

 var capture = new SecretType(); capture.i = ... Func func = capture.SecretMethod; 

Où:

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

Ceci est identique aux “méthodes anonymes”, mais avec une syntaxe différente.

Notez que les méthodes qui ne capturent pas l’état peuvent être implémentées en tant que méthodes statiques sans classe de capture.

Les arbres d’expression, en revanche … sont plus difficiles à expliquer: p

Mais (je n’ai pas de compilateur à la main, alors supportez-moi):

 int i = ... Expression> func = x => 2*x*i; 

Est-ce que quelque chose comme:

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

(sauf en utilisant la construction “memberof” inexistante, car le compilateur peut sortingcher)

Les arbres d’expression sont complexes, mais peuvent être déconstruits et inspectés – par exemple, pour les traduire en TSQL.

Les expressions lambda sont bien des fonctions anonymes, mais avec plus de polyvalence. Ces deux articles rédigés par MSDN contiennent de nombreuses informations sur les expressions lambda, leur utilisation, la priorité des opérateurs => , leur relation avec les fonctions anonymes et des suggestions d’utilisation avancées.

Expressions Lambda (MSDN)

=> Opérateur (MSDN)

Voici quelques exemples:

 public class C { private int field = 0; public void M() { int local = 0; Func f1 = () => 0; // f1 is a delegate that references a comstackr-generated static method in C Func f2 = () => this.field; // f2 is a delegate that references a comstackr-generated instance method in C Func f3 = () => local; // f3 is a delegate that references an instance method of a comstackr-generated nested class in C } } 

Une expression lambda est une méthode non nommée écrite à la place de délégué. Le compilateur le convertit soit en:

  • Une instance de délégué
  • Un arbre d’expression , de type Expression qui représente le code à l’intérieur, dans un modèle object traversable. Cela permet à l’expression lambda d’être interprétée à l’exécution.

Le compilateur résout donc les expressions lambda en déplaçant le code de l’expression dans une méthode privée.