Problem with delegate assignment in for-loop

I have an application that supports plugins (MEF). The plugins are UserControls WPF, which imports services.

The user can select the required plugin from the main application menu.

To do this, I use the following loop:

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

This works very well for a single item. But as soon as I have more than one plugin, all menu items are executed by the delegate of the last loop. Or at least using the Plugin.Control of the last loop.

How can i fix this? Thanks for any help.

+6
closures c # event-handling delegates
source share
1 answer

At each iteration of the loop, you need to β€œcapture” the value of the iterated value before using it in the close. Otherwise, the plugin in each delegate will point to the last value of the plugin instead of the value that it held while creating the anonymous function.

You can read a more detailed explanation from Eric Lippert here:

Closing a loop variable is considered harmful - Fabulous Adventures in Coding

In short, the correct way to write your foreach loop is:

 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); } 
+8
source share

All Articles