参加工作以来,拜读过很多大作。有好多书读的时候感觉大彻大悟,不自觉的发出‘哦。。。’这样的感叹。但是随着杀猪刀(时间)不断的飞逝,不仅给我脸上带来了皱纹,还带走了不少前人总结和归纳的知识点和那些我还没来得及吸收的宝贵财富。好记性不如烂笔头,我决定开始写一些读书的笔记和工作上的心得,最好是两者能够结合起来,把知识真正的自己转化成自己的能力。
下面进入正题。闭包在程序员的日常工作几乎无所不在,当然不仅是工作,面试的时候经常也会有相关的题目。看过很多博客园上的朋友都有解释,每次重温都有‘哦。。。’的感觉。对,是每次。。。可能是因为我才疏学浅的原因吧,有些大神解释得很深入,最后总结的又太精辟。这几天在重温C#本质论(第三版)(有一个声音飘过:你之前也没看完过。。。。)。里面提到了闭包,只是很小的一段,说的不算‘深入’(没有列出IL),但是绝对算得上浅出,这回我真的是大彻大悟,相信你看完也必须懂了。
为了更好的理解代码,需要用几行代码来说明一下Lamda表达式(匿名方法)的实现。和闭包一样,它们只是编译器玩的小把戏,为的实让我们用起来更爽一点。
class Program
{
static void Main(string[] args)
{
int[] items = new int[2];
for (int i = 0; i < items.Length; i++)
{
Console.WriteLine("Enter a integer:");
items[i] = int.Parse(Console.ReadLine());
}
var flag = Sort(items, (first, second) => { return first > second; });
if (flag)
Console.WriteLine("First Parameter is bigger");
else
Console.WriteLine("Second Parameter is bigger");
Console.Read();
}
static bool Sort(int[] items, Func<int,int,bool> method)
{
return method(items[0], items[1]);
}
}
上面一段代码很简单,比较两次输入的大小,其中使用了lambda表达式来传递了比较的方法,那么经过编译器编译之后呢,下面一段代码展示了编译器生产的CIL代码对应的C#代码:
class Program
{
static void Main(string[] args)
{
int[] items = new int[2];
for (int i = 0; i < items.Length; i++)
{
Console.WriteLine("Enter a integer:");
items[i] = int.Parse(Console.ReadLine());
}
var flag = Sort(items,Program.__AnonymousMethod_00000000);
if (flag)
Console.WriteLine("First Parameter is bigger");
else
Console.WriteLine("Second Parameter is bigger");
Console.Read();
}
static bool Sort(int[] items, Func<int,int,bool> method)
{
return method(items[0], items[1]);
}
private static bool Program.__AnonymousMethod_00000000(
int first, int second)
{
return first < second;
}
}
一目了然,编译器帮我们生成了一个static的函数。可能有人要问,跟闭包有什么关系呢?我们再看一段代码:
class Program
{
static void Main(string[] args)
{
int comparionCount = 0;
int[] items = new int[2];
for (int i = 0; i < items.Length; i++)
{
Console.WriteLine("Enter a integer:");
items[i] = int.Parse(Console.ReadLine());
}
var flag = Sort(items, (first, second) =>
{
comparionCount++;
return first > second;
});
if (flag)
Console.WriteLine("First Parameter is bigger");
else
Console.WriteLine("Second Parameter is bigger");
Console.WriteLine(string.Format("Items were compared {0} times", comparionCount));
Console.Read();
}
static bool Sort(int[] items, Func<int,int,bool> method)
{
return method(items[0], items[1]);
}
}
上面这一段代码闭包就出现了,函数内部读取了外部函数定义的变量。那编译器究竟干了什么呢,我们看下面的代码:
class Program
{
private sealed class class __LocalsDisplayClass_00000001
{
public int comparionCount;
public bool __AnonymousMethd_00000000(int first,int second)
{
comparionCount ++;
return first>second;
}
}
static void Main(string[] args)
{
__LocalsDisplayClass_00000001 locals =
new __LocalsDisplayClass_00000001 ();
locals .comparionCount =0;
int[] items = new int[2];
for (int i = 0; i < items.Length; i++)
{
Console.WriteLine("Enter a integer:");
items[i] = int.Parse(Console.ReadLine());
}
var flag = Sort(items,locals.__AnonymousMethd_00000000);
if (flag)
Console.WriteLine("First Parameter is bigger");
else
Console.WriteLine("Second Parameter is bigger");
Console.WriteLine(string.Format("Items were compared {0} times", comparionCount));
Console.Read();
}
static bool Sort(int[] items, Func<int,int,bool> method)
{
return method(items[0], items[1]);
}
}
被使用的局部变量被当作一个实例字段,包含在编译器生成的内部类中。
原文是这么说的:生成的__LocalsDisplayClass类成为闭包,他是一个数据结构(一个C#类),其中包含一个表达式以及对表达式进行求值所需的变量。
相信代码贴出来之后,就不需要过多的解释了。还有一些C#本质论的一些最佳实践和建议会陆续整理出来。再次推荐一下这本书,因为经验和基础的不同,每个人看、每次看感受和重点都会有所不同。
当然,第一篇博客,要留个纪念。感谢我的妻子对我的理解,允许我春节一个人窝在家里(没有回老家过年),有充足的时间边玩边看边学,你的支持和理解,就是我前进的动力!!!