代码之家  ›  专栏  ›  技术社区  ›  Marks

在for循环中分配代理时出现问题

  •  6
  • Marks  · 技术社区  · 15 年前

    我有一个应用程序,能够插件(mef)。 插件是导入服务的WPF用户控件。

    用户可以从应用程序的主菜单中选择所需的插件。

    为此,我使用以下循环:

    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。

    我怎么修这个?
    谢谢你的帮助。

    1 回复  |  直到 15 年前
        1
  •  9
  •   Justin Niessner    15 年前

    在循环的每次迭代中,在闭包中使用迭代值之前,必须“捕获”它的值。否则,每个委托中的插件将指向插件的最后一个值,而不是创建匿名函数时所保留的值。

    您可以在这里阅读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);
    }