2010-07-13 11 views
6

Possiedo un'applicazione in grado di plug-in (MEF). I plugin sono UserControls WPF che importano i servizi.Problema con l'assegnazione di delegati nel ciclo for-

L'utente può selezionare il plugin desiderato dal menu principale dell'applicazione.

Per fare questo, io uso il seguente ciclo:

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); 
} 

che funziona molto bene per un singolo elemento. Ma non appena ho più di 1 plugin, tutti i menu eseguono il delegato dell'ultimo ciclo. O almeno con il Plugin.Control dell'ultimo ciclo.

Come posso risolvere questo problema?
Grazie per qualsiasi aiuto.

+5

Mi piace vedere i tanti variazioni di questa domanda. – ChaosPandion

+0

@Chaos - in tal caso dovresti votare per chiudere;) – ChrisF

risposta

8

Su ogni iterazione del ciclo, è necessario "acquisire" il valore del valore iterato prima di utilizzarlo in una chiusura. In caso contrario, il plug-in di ciascun delegato punterà all'ultimo valore del plugin anziché al valore che ha mantenuto quando è stata creata la funzione anonima.

Si può leggere una più approfondita spiegazione di Eric Lippert qui:

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

In breve, il modo corretto di scrivere il ciclo foreach è:

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

Suppongo che includerai il link obbligatorio ai post del blog di Eric sull'argomento? (Chiusura della variabile del ciclo considerata dannosa.) –

+0

@Jon Skeet - Sì ... sta lavorando per ottenere il collegamento. –

+0

Dovremmo avere una rotazione per questa domanda :) (Poiché è difficile da cercare, non credo valga la pena chiuderlo come duplicato.) –