Почему в лямбда-выражение требуется включить временную переменную в foreach? - PullRequest
4 голосов
/ 25 марта 2012

Я читал C# 4 in a Nutshell и пришел к этому коду:

IQueryable<Product> SearchProducts (params string[] keywords)
{
  IQueryable<Product> query = dataContext.Products;

  foreach (string keyword in keywords)
  {
    string temp = keyword;
    query = query.Where (p => p.Description.Contains (temp));
  }
  return query;
}

Сразу после кода появляется «предупреждение», которое выглядит так:

The temporary variable in the loop is required to avoid the outer variable trap, where the same variable is captured for each iteration of the foreach loop.

Не понимаю, не понимаю, зачем нужна переменная temp. Что такое outter variable trap?

От: http://www.albahari.com/nutshell/predicatebuilder.aspx

Кто-нибудь может уточнить это?

Ответы [ 2 ]

5 голосов
/ 25 марта 2012

Поскольку существует только одна переменная с именем keyword, которая закрыта. Временная переменная, однако, отличается каждая итерация.

Таким образом, без временной переменной, когда лямбда выполняется позже , keyword оценивает последнее значение, которое было присвоено в цикле.

Другое решение, в некоторых случаях, состоит в том, чтобы заставить оценить (и в итоге получить List или около того).

2 голосов
/ 25 марта 2012

Проблема в том, что keyword меняется. Делегат => закрывается на текущем значении переменной, а не на том значении, которое оно имело в прошлом при создании делегата. Подробное объяснение есть в сообщении Эрика Липперта .

Эта классическая ошибка C та же ошибка:

#include <stdio.h> 
#include <pthread.h>

void * MyThreadFunction(void *x)
{
   printf("I am thread %d\n", * (int *) x);
   return NULL;
}

int main(void)
{
   int i;
   pthread_t t[10];
   void *ret;
   for(i=0; i<10; i++)
       pthread_create(&t[i], NULL, MyThreadFunction, (void *) &i);
   for(i=0; i<10; i++)
       pthread_join(t[i], &ret);
}

* (int *) x получает значение current , равное i, а не значение при создании потока.

...