我有一个能够插件(MEF)的应用程序。 插件是导入服务的WPF UserControl。
用户可以从应用程序的主菜单中选择所需的插件。
为此,我使用以下循环:
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);
}
单个项目的效果非常好。但是,只要我有一个以上的插件,所有菜单项都会执行最后一个循环的委托。或者至少使用最后一个循环的Plugin.Control。
我该如何解决这个问题? 谢谢你的帮助。
答案 0 :(得分:9)
在循环的每次迭代中,在闭包中使用迭代值之前,必须“捕获”迭代值的值。否则每个委托中的插件将指向插件的最后一个值,而不是创建匿名函数时它所持有的值。
您可以在此处阅读Eric Lippert的更深入的解释:
Closing over the loop variable considered harmful - Fabulous Adventures in Coding
简而言之,编写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);
}