Проблема с присвоением делегатов в для цикла

У меня есть приложение, которое способно к плагинам (MEF). Плагины являются WPF UserControls тот импорт сервисы.

Пользователь может выбрать требуемый плагин из главного меню приложения.

Чтобы сделать это, я использую следующий цикл:

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

Это работает очень прекрасное на единственный объект. Но как только у меня есть больше чем 1 плагин, все пункты меню выполняют делегата последнего цикла. Или по крайней мере с Плагином. Управление последнего цикла.

Как я могу зафиксировать это?
Спасибо за любую справку.

6
задан Justin Niessner 13 July 2010 в 13:26
поделиться

1 ответ

На каждой итерации цикла вы должны "перехватывать" значение итерируемого значения, прежде чем использовать его в закрытии. В противном случае Plugin в каждом делегате будет указывать на последнее значение Plugin вместо значения, которое он имел при создании анонимной функции.

Вы можете прочитать более подробное объяснение от Эрика Липперта здесь:

Закрытие переменной цикла считается вредным - 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);
}
9
ответ дан 10 December 2019 в 02:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: