2010-07-13 6 views
6

J'ai une application qui est capable de plugins (MEF). Les plugins sont des UserControls WPF qui importent des services.Problème avec l'affectation de délégués dans la boucle for

L'utilisateur peut sélectionner le plugin voulu dans le menu principal de l'application.

Pour ce faire, j'utiliser la boucle suivante:

foreach(IToolPlugin Plugin in ToolPlugins) 
{ 
    Plugin.Init(); 
    MenuItem PluginMenuItem = Plugin.MenuItem; //New MenuItem but with Header set. 
    PluginMenuItem.Click += new RoutedEventHandler(delegate(object o, RoutedEventArgs e) { DoSomething(Plugin.Control);}); 
    PluginsMenu.Items.add(PluginMenuItem); 
} 

Cela fonctionne très bien pour un seul élément. Mais dès que j'ai plus de 1 plugin, tous les menuitems exécutent le délégué de la dernière boucle. Ou au moins avec le Plugin.Control de la dernière boucle.

Comment puis-je résoudre ce problème?
Merci pour toute aide.

+5

J'adore voir les nombreux variations de cette question. – ChaosPandion

+0

@Chaos - dans ce cas, vous devriez voter pour fermer;) – ChrisF

Répondre

8

A chaque itération de la boucle, vous devez "capturer" la valeur de la valeur itérée avant de l'utiliser dans une fermeture. Sinon, le plugin dans chaque délégué pointera sur la dernière valeur de Plugin au lieu de la valeur qu'il contenait lors de la création de la fonction anonyme.

Vous pouvez lire une explication plus approfondie de Eric Lippert ici:

Closing over the loop variable considered harmful - Fabulous Adventures in Coding

En bref, la bonne façon d'écrire votre boucle foreach est:

foreach(IToolPlugin Plugin in ToolPlugins) 
{ 
    Plugin.Init(); 
    MenuItem PluginMenuItem = Plugin.MenuItem; 

    IToolPlugin capturedPlugin = Plugin; 

    PluginMenuItem.Click += 
     new RoutedEventHandler(delegate(object o, RoutedEventArgs e) { 
      DoSomething(capturedPlugin.Control); 
     }); 

    PluginsMenu.Items.add(PluginMenuItem); 
} 
+0

Je suppose que vous allez inclure le lien obligatoire vers les articles de blog d'Eric sur le sujet? (Fermeture sur la variable de la boucle considérée comme nuisible.) –

+0

@Jon Skeet - Oui ... travaillant sur l'obtention du lien. –

+0

Nous devrions avoir une rotation pour cette question :) (Comme il est difficile à chercher, je ne pense pas que ça vaut la peine de le fermer comme un doublon.) –