2010-07-13 20 views
6

Tengo una aplicación que es capaz de complementos (MEF). Los complementos son WPF UserControls que importan servicios.Problema al asignar delegados en for-loop

El usuario puede seleccionar el complemento deseado del menú principal de la aplicación.

Para ello, utilizo el siguiente bucle:

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

que funciona muy bien para un solo artículo. Pero tan pronto como tengo más de un complemento, todos los elementos de menú ejecutan el delegado del último ciclo. O al menos con el complemento. Control del último ciclo.

¿Cómo puedo solucionar esto?
Gracias por cualquier ayuda.

+5

Me encanta ver a los muchos variaciones de esta pregunta. – ChaosPandion

+0

@Chaos - en ese caso, debe votar para cerrar;) – ChrisF

Respuesta

8

En cada iteración del ciclo, debe "capturar" el valor del valor iterado antes de usarlo en un cierre. De lo contrario, el complemento de cada delegado señalará el último valor de Complemento en lugar del valor que tenía cuando se creó la función anónima.

Usted puede leer una explicación más detallada de Eric Lippert aquí:

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

En resumen, la forma correcta de escribir el bucle foreach es:

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

Supongo que va a incluir el enlace obligatorio a las publicaciones del blog de Eric sobre el tema. (Cerrando la variable de bucle considerada perjudicial.) –

+0

@Jon Skeet - Sip ... trabajando para obtener el enlace. –

+0

Deberíamos tener un turno para esta pregunta :) (Como es difícil de buscar, no creo que valga la pena cerrarlo como un duplicado). –