IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Evénement et comportement étrange sur l'appel du délégué


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre expérimenté
    Avatar de StormimOn
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2005
    Messages
    2 593
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2005
    Messages : 2 593
    Par défaut Evénement et comportement étrange sur l'appel du délégué
    Bonjour,

    Je rencontre un comportement que je ne comprends pas. C'est probablement tout bête, mais si quelqu'un peut m'expliquer le pourquoi du comment histoire que je me couche moins bête ce soir

    Soit les classes Item et OtherItem
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Item
    {
        public Action Action { get; set; }
    }
     
    class OtherItem
    {
        public event EventHandler Click = delegate { };
     
        public void ClickRequested()
        {
            Click(this, EventArgs.Empty);
        }
    }
    et le code suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    class Program
    {
        static void Main(string[] args)
        {
            Item item1 = new Item { Action = delegate { Console.WriteLine("Item 1"); } };
            Item item2 = new Item { Action = delegate { Console.WriteLine("Item 2"); } };
            Item item3 = new Item { Action = delegate { Console.WriteLine("Item 3"); } };
     
            List<Item> items = new List<Item> { item1, item2, item3 };
            List<OtherItem> otherItems = new List<OtherItem>();
     
            foreach (Item item in items)
            {
                OtherItem otherItem = new OtherItem();
                otherItem.Click += delegate { item.Action(); };
                otherItems.Add(otherItem);
            }
     
            foreach (OtherItem otherItem in otherItems)
            {                
                otherItem.ClickRequested();
            }
     
            Console.ReadLine();
        }
    }
    Alors que je m'attends à avoir très logiquement en sortie
    Item 1
    Item 2
    Item 3
    le code précédent affiche en réalité
    Item 3
    Item 3
    Item 3
    Si je modifie légèrement la première boucle foreach en stockant dans une variable l'objet énuméré
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    foreach (Item item in items)
    {
        Item i = item;
        OtherItem otherItem = new OtherItem();
        otherItem.Click += delegate { i.Action(); };
        otherItems.Add(otherItem);
    }
    Le comportement est alors celui attendu

    Bref, je ne suis pas sûr de comprendre le pourquoi de la chose. Est-ce lié à la capture de variable de la méthode anonyme ? Bien que je ne vois pas pourquoi.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Ah, voilà une question intéressante

    Citation Envoyé par StormimOn Voir le message
    Est-ce lié à la capture de variable de la méthode anonyme ?
    Oui, c'est tout à fait ça. En fait, dans ton foreach, ce n'est pas la valeur de la variable item qui est capturée, mais la variable elle-même. Il y a une explication un peu plus complète sur le site de Jon Skeet.

    Sinon, juste pour le fun, voilà une version un peu modifiée de ton code, utilisant les expressions Linq pour mieux comprendre ce qui se passe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
                ...
     
                foreach (Item item in items)
                {
                    OtherItem otherItem = new OtherItem();
                    Expression<EventHandler> expr = (sender, e) => item.Action();
                    Console.WriteLine(expr);
                    otherItem.Click += expr.Compile();
                    otherItems.Add(otherItem);
                }
     
                ...
    Le résultat est le suivant :

    (sender, e) => Invoke(value(ConsoleApplication1.Program+<>c__DisplayClassa).item.Action)
    (sender, e) => Invoke(value(ConsoleApplication1.Program+<>c__DisplayClassa).item.Action)
    (sender, e) => Invoke(value(ConsoleApplication1.Program+<>c__DisplayClassa).item.Action)
    Item 3
    Item 3
    Item 3
    On voit donc que l'expression ne prend pas directement la valeur de item, mais qu'elle y accède en tant que membre d'une classe générée par le compilateur (ConsoleApplication1.Program+<>c__DisplayClassa)

    Juste pour info, voilà le code de cette classe générée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    [CompilerGenerated]
    private sealed class <>c__DisplayClassa
    {
        // Fields
        public Program.Item item;
     
        // Methods
        public <>c__DisplayClassa();
    }

  3. #3
    Membre expérimenté
    Avatar de StormimOn
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2005
    Messages
    2 593
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2005
    Messages : 2 593
    Par défaut
    Ok je comprends mieux. Je connaissais le principe, mais pas la distinction sur le fait qu'une variable pouvait être commune au différentes méthodes anonymes en fonction de l'endroit où elle est déclarée.

    Merci

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Comportement étrange sur le UNION
    Par tribaleur dans le forum Requêtes
    Réponses: 11
    Dernier message: 08/08/2014, 09h42
  2. Comportement étrange sur iPad
    Par elvan49 dans le forum Mise en page CSS
    Réponses: 3
    Dernier message: 18/10/2011, 07h13
  3. Comportement étrange sur un bulleted list
    Par stroumfs dans le forum ASP.NET
    Réponses: 1
    Dernier message: 14/10/2008, 15h51
  4. [2.0] comportement étrange sur condition sur string.indexOf
    Par franculo_caoulene dans le forum VB.NET
    Réponses: 26
    Dernier message: 18/06/2008, 12h09
  5. Comportement étrange ksh sur linux
    Par hugo123 dans le forum Shell et commandes GNU
    Réponses: 6
    Dernier message: 09/08/2006, 10h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo