从集合中检索lambda表达式

4
我对C#中的Lambda表达式非常陌生,我很难理解它们如何在集合中存储/检索。
我正在尝试编写一个程序来创建一个包含10个Funcs的列表,例如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]时,得到了相同的结果。我错过了什么?
3个回答

7

通过将i复制到一个新变量中,使其在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));

6

谢谢您发布那个链接。有趣的是,C# 似乎被锁定在这个警告中,因此依赖于维护 i 的最后一个值(在我的情况下)的开发人员不会使他们的程序出现问题。 - bufferz
2
在这里,“有趣”意味着“非常烦人”。 :-) - Eric Lippert

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

更多信息请参见此博客文章

顺便提一下,在调用委托时,您不需要编写func.Invoke(params);您可以直接编写func(params)


这是对我的主要问题的3个正确答案的胜负相当,但是你最后关于func(params)的评论得到了+1。谢谢! - bufferz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接