Лямбда-выражение с параметром внутри. Неожиданный результат в VS2008 и хорошо работает в VS2013

1

Я не знаю, как объяснить проблему именно в слове. Я написал код, чтобы воспроизвести проблему, и я изо всех сил старался сделать код легким для чтения.

delegate string del();
static void Main(string[] args)
{

    string[] ss = { "a", "b" };
    Dictionary<string, del> dic = new Dictionary<string, delSS>();
    foreach (string s in ss) {
        dic[s] = () => s;
    }
    foreach (string s in ss) {
        System.Console.WriteLine("{0}:{1}", s, dic[s]());
    }
    System.Console.ReadLine();
}

Я создал два выражения лямбда для "a" и "b", для "a" он возвращает "a", а для "b" он возвращает "b". Делегаты сохраняются в словаре с именем dic. И я называю их по-разному. Ожидаемый результат

a:a
b:b

и это результат VS2013. Но в VS2008 результат

a:b
b:b

Я пробовал версии.NET Framework от 3.0 до 4.5 в VS2013, и все они дают тот же результат. Я также пробовал 3.0 и 3.5 в VS2008, и они тоже дают одинаковые результаты. Я думал, это означает, что это не ошибка в Framework, а ошибка компилятора. Я разрабатываю приложение для WinCE 6.0, которое поддерживается только в VS2008 и более ранних версиях. Вот почему я должен использовать VS2008. Я нашел проблему, когда я отлаживаю приложение WinCE. Я думал, что это ошибка Compact Framework, но это оказалось ошибкой VS2008. Кто-нибудь знает, как это исправить?

Теги:
lambda

3 ответа

1

Захват переменной цикла внутри замыкания является сложным. Приятно, что VS2013 сортирует его для вас, но я не думаю, что это безопасно использовать вообще.

Джон Скит объясняет это здесь (и в своих книгах): Захваченная переменная в цикле на С#. Инструменты качества кода, такие как Resharper, вызывают предупреждение в любое время, когда вы пытаетесь это сделать.

1

Ну компилятор стал лучше, я это даю;)

Пытаться

   foreach (string s in ss) {
        var closed = s;
        dic[s] = () => closed;
    }

Это создаст новую переменную/значение для каждого s чтобы закрытие не указывало на ваши s которые будут мутироваться циклом foreach до конца.

0

Вот решение. Я сделал следующую модификацию, и я попробовал ее в vs2008, он отлично выполняет делегирование строки del (string sr);

    static void Main( )
    {

        string[] ss = { "a", "b" };
        Dictionary<string, del> dic = new Dictionary<string, del >();
        foreach (string s in ss)
        {
            dic[s] = (sr) => sr;
        }
        foreach (string s in ss)
        {
            System.Console.WriteLine("{0}:{1}", s, dic[s].Invoke(s));
        }
        System.Console.ReadLine();
    }
  1. Теперь у делегата del есть параметр sr
  2. Вы должны вызвать делегата в точке использования и передать в переменной 's'

Тот факт, что вы используете делегат, подразумевает, что вы должны использовать преимущество того факта, что вы можете передать параметр в делегат. Когда вы помещаете переменную в функцию лямбда, это делает CLR, чтобы выбрать последнюю позицию указателя цикла foreach как переменной s для всех.

  • 0
    добавить делегат строки del (строка sr); перед основным ()

Ещё вопросы

Сообщество Overcoder
Наверх
Меню