NET也有闭包
在.NET中,函数并不是第一级成员,所以并不能像JavaScript那样通过在函数中内嵌子函数的方式实现闭包,通常而言,形成闭包有一些值得总结的非必要条件:
嵌套定义的函数。
匿名函数。
将函数作为参数或者返回值。
在.NET中,可以通过匿名委托形成闭包:
delegatevoidMessageDelegate();
staticvoidMain(string[]args)
{
stringvalue="Hello,Closure.";
MessageDelegatemessage=delegate()
{
Show(value);
};
message();
}
privatestaticvoidShow(stringmessage)
{
Console.WriteLine(message);
}
事实上,大部分支持闭包的高级语言中,函数都是第一级成员,函数可以作为参数传递,也可以作为返回值返回,或者作为函数变量。而在.NET中,这一切都可以通过委托来实现,关于委托的详情请参考9.7节“一脉相承:委托、匿名方法和Lambda表达式”,所以上述逻辑也可以通过Lambda表达式实现更简单的代码。
反编译上述示例为IL代码:
.classprivateautoansibeforefieldinitProgram
extends[mscorlib]System.Object
{
.methodprivatehidebysigstaticvoidMain(string[]args)cilmanaged
{
//省略
}
.classautoansisealednestedprivatebeforefieldinit<>c__DisplayClass1
extends[mscorlib]System.Object
{
.custominstancevoid[mscorlib]System.Runtime.CompilerServices.CompilerGenerated Attribute::.ctor()
.methodpublichidebysigspecialnamertspecialnameinstancevoid.ctor()cilmanaged
{
//省略
}
.methodpublichidebysiginstancevoid<Main>b__0()cilmanaged
{
//省略
}
.fieldpublicstringvalue
}
}
通过匿名方法将自动形成闭包,自由变量value被包装在一个内部类(闭包)中,并升级为实例成员,即使创建该变量的方法执行结束,该变量也不会释放,而是在所有回调函数执行之后才被GC回收。自由变量value的生命周期被延长,并不局限为一个局部变量。生命周期的延迟,是闭包带来的福利,但是也往往带来潜在的问题,造成更多的消耗。
1.闭包与函数
像对象一样的操作函数,是闭包发挥的最大作用,从而实现了模块化的编程方式。不过,闭包与函数并不是一回事儿。
闭包是函数与其引用环境组合而成的实体。不同的引用环境和相同的函数可以组合产生不同的闭包实例。
函数是一段可执行的代码体,在运行时不会由于上下文环境发生变化。
2.应用闭包
闭包,是函数式编程的精灵,在.NET平台中,这个精灵同样带来诸多方面的应用,典型的表现主要体现在以下几方面。
定义控制结构,实现模块化应用。闭包实现了以最简单的方式开发粒度最小的模块应用,实现一定程度的算法复用,下例的ForEach为遍历数组元素提供了复用基础,对于加法运算和减法运算而言,在闭包中改变引用环境变量的值,达到最小粒度的模块控制效果。
staticvoidMain()
{
int[]values={1,2,3,4,5,6,7,8,9,10};
intresult1=0;
intresult2=100;
values.ForEach(x=>result1+=x);
values.ForEach(x=>result2-=x);
Console.WriteLine(result1);
Console.WriteLine(result2);
}
多个函数共享相同的上下文环境,进而实现通过上下文变量达到数据交流的作用。
staticvoidMain()
{
intvalue=100;
IList<Func<int>>funcs=newList<Func<int>>();
funcs.Add(()=>value+1);
funcs.Add(()=>value-2);
foreach(varfinfuncs)
{
value=f();
Console.WriteLine(value);
}
}
数据共享为不同函数的操作间传递数据带来方便,但是这把双刃剑有时又为不需要共享数据的场合带来问题,以上例而言,value变量将在不同的操作中() => value + 1和() => value – 2间共享数据。如果不希望在两次操作间传递数据,需要特别注意引入中间量协调:
staticvoidMain()
{
intvalue=100;
IList<Func<int>>funcs=newList<Func<int>>();
funcs.Add(()=>value+1);
funcs.Add(()=>value-2);
foreach(varfinfuncs)
{
intv=f();
Console.WriteLine(v);
}
}
本文节选自《你必须知道的.NET(第2版)》一书
图书详细信息:http://blog.csdn.net/broadview2006/article/details/6673353
分享到:
相关推荐
离散数学-关系,集合,求自反闭包,对称闭包,传递闭包 离散数学-关系,集合,求自反闭包,对称闭包,传递闭包 离散数学-关系,集合,求自反闭包,对称闭包,传递闭包 离散数学-关系,集合,求自反闭包,对称闭包...
在2013年发布的 JavaSE8 中包含一个叫做 Lambda Project 的计划,在 JSR-335 草案 中有描述。 JSR-335 将闭包引入了 Java 。闭包在现在的很多流行的语言中都存在,例如 C++、C# 。闭包允许我 们创建函数指针,并把...
3) 计算属性集闭包的算法,在课件里有详细说明。方法很简单,但用文字描述很抽象。。。。不解释。。。 4) 计算函数依赖的闭包。此步骤不作要求,但要会方法。个人总结:将所有属性元素组成一个集合(域)记为R;...
实验目的:熟悉warshall算法,掌握求关系的自反闭包,对称闭包和传递闭包的方法。 实验内容:从键盘输入一个关系的关系矩阵,自动求出自反闭包、对称闭包和传递闭包。 计算传递闭包用Warshall算法。 #include...
C语言实现三种闭包算法,能够实现传递,自反,对称闭包
内存泄露,闭包 内存泄露,闭包 内存泄露,闭包
闭包是ECMAScript (JavaScript)最强大的特性之一,但用好闭包的前提是必须理解闭包。闭包的创建相对容易,人们甚至会在...而闭包工作机制的实现很大程度上有赖于标识符(或者说对象属性)解析过程中作用域的角色。
计算NFA中各个状态的闭包,从键盘上输入一个NFA的描述信息(输入格式自行定义),将 该NFA的描述信息保存到合适的数据结构中,然后计算出NFA中每个状态的ε_closure。
匿名函数,也称为拉姆达函数,是一种使用JavaScript函数的强大方式。以下总结了匿名函数的特点: 任何函数表达式从技术上说都是匿名函数,因为没有引用它们的确定的方式; 在无法确定如何引用函数的情况下,递归...
Swift之闭包ClosureDemo
用矩阵求对称闭包。简洁,轻松学习,相互交流。
闭包文件
Javascript 闭包完整解释
JS闭包可被利用的常见场景。值得保留的文档。值得一看
Python闭包实例closure.py 简单示例闭包的使用 简单示例闭包的使用
js闭包的详细讲解
用矩阵求自反闭包。容易理解,轻松学习,交流经验。
离散数学 闭包运算 传递闭包 自反闭包 对称闭包 warshell算法 普通算法 有界面 java编程
原子闭包系统, 原子闭包算子和原子全蕴含系统,杨海建,李庆国,本文引进了原子闭包系统,原子闭包算子以及原子全蕴含系统等概念, 研究了它们之间的相互关系, 给出了由原子闭包系统来表示有限原子�
迭代器、代码块、闭包迭代器、代码块、闭包