Variables Locales et Expressions Lambda

This article is available in english.

Après une petite discussion avec Eric Lippert à propos d'un post sur l'utilisation dans une expression lambda d'une variable locale déclarée dans une boucle foreach, Eric m'a fait remarquer que le morceau de code suivant :

    int a = 0;
    Action action = () => Console.WriteLine(a);
    action();


N'est pas étendu par le compilateur vers ce code :

    [CompilerGenerated]
    private sealed class <>c__DisplayClass1
    {
       public int a;

       public void <Main>b__0()
       {
          Console.WriteLine(this.a);
       }
    }

    void Main()
    {

        int a = 0;

       var display = new <>c__DisplayClass1();
       display.a = a;

       var action = new Action(display.<Main>b__0);

       action();
    }

J'ai fait une supposition sur le fait qu'une variable locale était simplement copiée dans la "display class" lorsqu'elle n'est pas utilisée après la création de la lambda, ce qui n'est pas le cas.

Si l'on prend un exemple un peu différent, avec le code suivant :

    int a = 0;
    Action action = () => Console.WriteLine(a);
    a = 42;
    action();


Ma supposition aurait fait en sorte que l'exécution de ce dernier code aurait affiché 0. Or ce n'est pas correct car les expressions lambda (et les méthodes anonymes) "capturent" la variable et non la valeur; l'exécution doit donc afficher 42.

En fait, le dernier morceau de code est étendu de la manière suivante :

    var display = new <>c__DisplayClass1();

    display.a = 0;

    var action = new Action(display.<Main>b__0);

    display.a = 42;

    action();

On peut constater dans les faits que la variable qui était auparavant locale, donc sur la pile, a été "promue" en tant que champ membre de la "DisplayClass". Cela veut dire aussi que toutes les références faites à cette variable "locale", aussi bien à l'intérieur qu'à l'extérieur de la lambda, sont remplacée vers l'instance courante de "DisplayClass".

C'est finalement très simple, mais on sent que la "magie" derrière le sucre syntaxique de C#3.0 a été assez bien pensée !

Je finirais par un grand merci à Eric Lippert qui a pris le temps de me répondre, malgré qu'il soit très probablement surchargé par le développement de C# 4.0. (avec la contravariance des types génériques, yey !)
Publié vendredi 21 novembre 2008 00:51 par jay
Classé sous ,
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires


Les 10 derniers blogs postés

- [ #Yammer ] From Mailbox to Yammer and back / De votre messagerie vers Yammer et retour ! par Le blog de Patrick [MVP SharePoint] le 09-15-2014, 11:31

- [ #Office 365 ] New service settings panel / Nouveau panneau de paramétrage des services par Le blog de Patrick [MVP SharePoint] le 09-11-2014, 08:50

- Problème de déploiement pour une démo SharePoint/TFS? par Blog de Jérémy Jeanson le 09-10-2014, 21:52

- [ #Office365 ] Delve first impressions / Premières impressions sur Delve par Le blog de Patrick [MVP SharePoint] le 09-09-2014, 16:57

- [ #Office365 ] How to change Administration console language ? / Comment changer la langue de la console d’administration ? par Le blog de Patrick [MVP SharePoint] le 09-09-2014, 08:25

- [ #SharePoint 2013 ] Suppression de bases de données en état “Pas de Réponse” par Le blog de Patrick [MVP SharePoint] le 09-04-2014, 14:10

- Changer l’adresse d’une ferme Office Web Apps associée à SharePoint par Blog de Jérémy Jeanson le 09-01-2014, 22:21

- Une ferme #SharePoint 2013 dans @Azure en quelques clics (1ère partie) ! par Le blog de Patrick [MVP SharePoint] le 08-28-2014, 18:52

- SharePoint 2013: Préparation de la migration - Création des site Templates dans 2010 et 2013 par Blog Technique de Romelard Fabrice le 08-20-2014, 16:31

- [ #Yammer ] How to change interface language ? Comment changer la langue de l’interface ? par Le blog de Patrick [MVP SharePoint] le 08-20-2014, 14:21