闭包: 闭包是能够读取其他函数内部变量的函数
c#的实现是使用lambda表达式
先来尝试一下:
Console.WriteLine("begin");
for(int i=0,j=0;i<10;i++,j++){
Action action = ()=>{
Thread.Sleep(10);
Console.WriteLine("i:"+i+",j:" + j);
};
action();
}
Console.WriteLine("end");
输出结果
在lambda中使用了其他函数的内部变量 i 和 j 实现了闭包。
和我们想象中的一样,输出0-9。
我们再来看个多线程的例子
Console.WriteLine("begin");
for(int i=0,j=0;i<10;i++,j++){
Action action = ()=>{
Thread.Sleep(10);
Console.WriteLine("i:"+i+",j:" + j);
};
Task.Factory.StartNew(
action
);
}
Console.WriteLine("end");
输出结果
看到输出结果是不是心里有点凉凉 ,输出全是10,首先是输出了 begin 和 end,在函数中的i 和 j肯定是10
但是 lambda 表达式中的值 也是 10,那应该有两种可能, 第一种 lambda中的 i 与 函数中的 i 是同一个,
还有一种是 lambda 中的是在 lambda执行的时候取了 函数中的 i的值,因为 lambda 表达式是多线程执行的,它有可能晚了一步执行。
再来看个例子
Console.WriteLine("begin");
for(int i=0,j=0;i<10;i++,j++){
Action<object> action = (a)=>{
Thread.Sleep(10);
Console.WriteLine("i:"+a+",j:" + j);
};
Task.Factory.StartNew(
action,i
);
}
Console.WriteLine("end");
输出结果
这次我把 i 作为 lambda的一个参数值传递,这时候 i在我们的意料之中0-9都有,顺序不一致是因为多线程执行顺序有先有后。
再来个单线程的
int i = 0;
int j = 0;
Action action =
()=>{
Thread.Sleep(10);
Console.WriteLine("i:"+i+",j:" + j);
i++;
};
action();
i = 20;
Console.WriteLine("ii:" + i + ",jj:" + j);
action();
Console.WriteLine("ii:" + i + ",jj:" + j);
输出结果
这次可以看出,闭包中修改的值影响到了函数本身内部变量的值,函数本身变量的值的修改也影响到了闭包的值,那应该就是 闭包中的值和函数本身的值是同一个。
翻阅了几篇文章发现闭包被编译成了一个类。
拿最后一个例子来举例,会被编译成类似以下代码:
class TmpClass{
public int i;
public int j;
public void method(){
Thread.Sleep(10);
Console.WriteLine("i:"+i+",j:" + j);
i++;
}
}
static void Procedure(){
TmpClass tmpclass = new TmpClass{
i=0,
j=0
};
tmpclass.method();
tmpclass.i = 20;
Console.WriteLine("ii:" + tmpclass.i + ",jj:" + tmpclass.j);
tmpclass.method();
Console.WriteLine("ii:" + tmpclass.i + ",jj:" + tmpclass.j);
}
lambda 表达式在多线程中使用外部函数内部变量,值类型最好还是使用参数传递,不容易出错。引用类型最好还是不要这么用吧!当然看实际情况。好吧,我又一堆代码需要重新调整啦。知识点还是得学习的深入一点。少吃点亏。