Lamda引起的一个问题
撰写于 2019-07-03 修改于 2019-07-03 分类 C#
##Lamda引起的一个问题
在C#中, Lamda表达式已经不是什么新鲜的东西,广泛使用在各个地方,跟 Action Delegate Func等这些委托没有本质却别,最近在使用是,遇到了常见的一种问题,在其他脚本Lua,Js中都能遇到,面试中也常遇到,就记录一下。先看一下代码演示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15static void Main(string[] args)
{
List<Action> callFunc = new List<Action>();
for (int i = 0; i < 5; i++)
{
callFunc.Add(() => Console.WriteLine("current index is:" + i));
}
foreach (var item in callFunc)
{
item();
}
Console.ReadKey();
}
以上代码输出是什么呢?预期的输出是:
current index is:0
current index is:1
current index is:2
current index is:3
current index is:4
但实际输出是:
current index is:5
current index is:5
current index is:5
current index is:5
current index is:5
为什么会这样呢?因为Lamda的一个特性:保存上下文。就是会保留当前执行环境内所有变量的值,在Lamda表达式中依旧可以访问这些变量。注意:是访问这些值,而不是复制这些值。当执行callFunc
中的Lamda表达式时,会去寻找定义该表达式时上下文中存在的i
,显然,i
是在定义Lamda表达式的for
循环中声明的,在内存中只有一份这样的数据,所有Lamda表达式访问的都是这同一个数据,当for循环执行完时:i=5
,因此所有Lamda表达式中访问到的i
值都是5。
那怎么才能得到预期结果呢?很显然,我们需要为每个Lamda创造一个单独的执行环境,也就是说,每个执行环境中的i
都是一份拷贝,互不相干。因此需要包装一下Lamda表达式, 方法如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18static void Main(string[] args)
{
List<Action> callFunc = new List<Action>();
Func<int, Action> generateCallFunc = (i) => { return () => Console.WriteLine("current index is:" + i); };
for (int i = 0; i < 5; i++)
{
callFunc.Add(generateCallFunc(i));
}
foreach (var item in callFunc)
{
item();
}
Console.ReadKey();
}
generateCallFunc
就是一个函数,传入i
,这样生成的每个Lamda就会有一个i
的拷贝,每个Lamda在执行时,就会访问当前上下文中的i
,这样就互不干涉,可以达到预期结果!