我正在阅读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
有人可以澄清一下吗?
答案 0 :(得分:5)
因为只有一个名为keyword
的一个变量被关闭。但是,临时变量在每次迭代时不同。
因此,如果没有临时变量,当lambda 稍后执行时,keyword
将计算它在循环中分配的最后一个值。
在某些情况下,另一种解决方案是强制评估(并最终得到List
等等。
答案 1 :(得分:2)
问题在于keyword
正在发生变化。 =>
委托关闭变量的当前值,而不是创建委托时过去的值。在Eric Lippert's blog post中有详细解释。
这个经典的C bug也是同样的错误:
#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
获取{em>当前值i
,而不是创建线程时的值。