.Net 闭包理解

.Net 闭包理解#

这个东西初看是比较难懂,但是一旦理解之后就很容易了,做笔记以加深印象。且看这题

example.1

class Program
{
static void Main(string[] args)
{
var actions = new List();

for (int i = 0; i < 5; i++)
{
actions.Add(() =>
{
Print(i);
});
}

actions.ForEach(x => x());
}

private static void Print(int i)
{
Console.WriteLine(i);
}
}

运行一下,结果都是5,Why?首先我们都知道,程序执行一个函数的时候,会将这个函数中用到的局部
变量压入一个栈中,退出这个函数的时候,会将栈中的数据清空。上面的代码,第一个Print函数用的i
值应该是第一个i(也就是0)所在地址的值,但是自加之后,地址变了,那么第一个Print函数用的i(也就是0)去
哪里了?我理解的话应该就是变成了一个不安全的地址,访问这个值就会出现问题。为了避免这种情况
的发生,.Net是如何处理的呢,那就是在所有Print函数执行的时候,不让这个i被清理,于是提升了i的
作用域(这个现象就叫闭包),我换个写法

example.2

class Program
{
private static int _i;

static void Main(string[] args)
{
var actions = new List();

for (_i = 0; _i < 5; _i++)
{
actions.Add(() =>
{
Print(_i);
});
}

actions.ForEach(x => x());
}

private static void Print(int i)
{
Console.WriteLine(i);
}
}

_注意:_此时是不存在闭包现象的,当然也别以为.Net就是这么做的,并不是。通过IL反汇编工具查看
example.1的代码,发现它把i封装到了一个匿名的类中,可以这么想,要使一个东西在栈上不被清理,
那就把它放到堆上...,于是用了个匿名类把i当成其属性,代码如下:

class Program
{
static void Main(string[] args)
{
var actions = new List();

var myClass = new MyClass();

for (var i = 0; i < 5; i++)
{
myClass.i = i;

actions.Add(() =>
{
Print(myClass);
});
}

myClass.i++;

actions.ForEach(x => x());
}

private static void Print(MyClass myClass)
{
Console.WriteLine(myClass.i);
}
}

internal class MyClass
{
public int i
{
get; set;
}
}

如果我们要避免这种情况,该如何做?那就相当于上诉代码每一个循环使用一个新的MyClass

class Program
{
static void Main(string[] args)
{
var actions = new List();

for (var i = 0; i < 5; i++)
{
var myClass = new MyClass();

myClass.i = i;

actions.Add(() =>
{
Print(myClass);
});
}

actions.ForEach(x => x());
}

private static void Print(MyClass myClass)
{
Console.WriteLine(myClass.i);
}
}

internal class MyClass
{
public int i
{
get; set;
}
}

其实申明MyClass这一步也可以省了,就是如下

class Program
{
static void Main(string[] args)
{
var actions = new List();

for (var i = 0; i < 5; i++)
{
var i1 = i;
actions.Add(() =>
{
Print(i1);
});
}

actions.ForEach(x => x());
}

private static void Print(int i)
{
Console.WriteLine(i);
}
}

其实上面这个写法是Resharper提示闭包之后给出的解决方案。
以上,就是我看了别人的一些理解,再加上自己的一些理解推敲出来的东西,有许多地方是模糊的,表面的,但
闭包这东西,不理解好像也没什么影响,这里起个抛砖引玉的作用,欢迎斧正拍砖。

posted @ 2016-03-28 22:24  UncleNull  阅读(881)  评论(0)    收藏  举报