委托和lambda表达式任务

时间:2016-05-11 13:16:57

标签: c# .net

你可以用委托和lambda表达式解释一个例子

List<Func<int>> list = new List<Func<int>>(); 
 for (int i = 0; i < 10; i++)
 {
     list.Add(() => i);
 }
 foreach (var func in list)
 {
      Console.WriteLine(func());
 }

据我所知,我有List的引用方法没有params并返回Int,但为什么它从循环中返回10倍的最大值?这个怎么运作? THX!

4 个答案:

答案 0 :(得分:4)

当你这样做时会关闭:

(() => i)

lambda获取原始变量i,而不是副本,因此你得到10次 - 因为在调用delegate时i的原始值是10(循环之后)

如果更改代码并添加本地临时变量,则会得到0 1 2 3 4 5 6 7 8 9:

 for (int i = 0; i < 10; i++)
 {
     int j = i;
     list.Add(() => j);
 }

您可以在此处阅读有关闭包的内容: Closures

答案 1 :(得分:1)

原因是lambda () => i 捕获局部变量i。这意味着i在添加到列表中时不会被评估,但是当您实际使用()调用lambda时。

当您的代码(Console.WriteLine(func());)发生这种情况时,i的值已经10,因为for循环已经完成。

如果你想避免这种行为,你必须将i的值复制到一个局部变量中,该变量在创建lambda后不会改变

for (int i = 0; i < 10; i++)
{
     int tmp = i;
     list.Add(() => tmp);
}

答案 2 :(得分:1)

当你在委托方法中传递变量时,它是它的链接,而不是它在委托中使用的值。

我们创建功能列表:

 List<Func<int>> list = new List<Func<int>>(); 

这里我们使用函数初始化列表,每个函数都应该使用对内存的引用,其中i变量在被触发时存储:

 for (int i = 0; i < 10; i++)
 {
     list.Add(() => i);
 }

现在是时候触发每个函数了,但此时for循环已经完成执行并且i变量保持其最终值为10.请记住,委托总是可以找到参数,因为它保存了引用它。它不能被垃圾收集:

 foreach (var func in list)
 {
      // by the time we do it it has value of 10
      Console.WriteLine(func());
 }

答案 3 :(得分:0)

实际上lambda表达式是一个委托,你在循环结束后调用它,那时i的值 10 ,所以当代表被调用时,他们都有i 10 因为关闭而使用相同的副本,您需要写为@Roma建议让它按预期工作,否则它会,

这个:

for (int i = 0; i < 10; i++)
 {
     list.Add(() => i);
 }

可以看作:

 int i;
 for (i=0; i < 10; i++)
 {
     list.Add(() => i);
 }