我对C#中的lambda表达式非常陌生,而且我很难概念化它们在集合中的存储/检索方式。
我正在尝试以编程方式创建10个Func的列表 x => x + 1,x => x + 2 等作为测试。 我想要的输出是 0,1,2,3,4,5,6,7,8,9
这是我的代码:
var list = new List<Func<int, int>>();
for (int i = 0; i < 10; i++)
{
Func<int, int> func = x => x + i;
Console.WriteLine("a) " + func.Invoke(0)); //returns 0,1,2,3,4,5,6,7,8,9
list.Add(func);
Console.WriteLine("b) " + list[i].Invoke(0)); //returns 0,1,2,3,4,5,6,7,8,9
}
foreach (var func in list) //returns 10,10,10,10,10,10,10,10,10,10
Console.WriteLine("c) " + func.Invoke(0));
for(int i = 0; i < list.Count; i++) //returns 10,10,10,10,10,10,10,10,10,10
Console.WriteLine("d) " + list[i].Invoke(0));
将 Func 数组替换为 List [Func] 时,我得到相同的结果。
我错过了什么?
答案 0 :(得分:7)
通过将lambda复制到一个新变量中使我成为lambda的本地:
var list = new List<Func<int, int>>();
for (int i = 0; i < 10; i++)
{
var temp = i;
Func<int, int> func = x => x + temp;
Console.WriteLine("a) " + func.Invoke(0)); //returns 0,1,2,3,4,5,6,7,8,9
list.Add(func);
Console.WriteLine("b) " + list[i].Invoke(0)); //returns 0,1,2,3,4,5,6,7,8,9
}
foreach (var func in list) //returns 0,1,2,3,4,5,6,7,8,9
Console.WriteLine("c) " + func.Invoke(0));
for (int i = 0; i < list.Count; i++) //returns 0,1,2,3,4,5,6,7,8,9
Console.WriteLine("d) " + list[i].Invoke(0));
答案 1 :(得分:6)
我认为你看到了这里描述的行为:
答案 2 :(得分:4)
你的问题是lambda表达式捕获你用来定义它的变量。
由于整个循环生成的列表共享相同的变量,所有代理将返回10。
要解决此问题,请在生成循环内声明一个单独的变量,将其分配给i
,然后在lambda表达式中使用它。
例如:
var list = new List<Func<int, int>>();
for (int dontUse = 0; dontUse < 10; dontUse++) {
var i = dontUse;
Func<int, int> func = x => x + i;
list.Add(func);
}
foreach (var func in list)
Console.WriteLine("c) " + func(0));
有关详细信息,请参阅this blog post
顺便说一下,在调用代理人时,你不需要写func.Invoke(params)
;你可以简单地写func(params)
。