博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NET也有闭包
阅读量:5934 次
发布时间:2019-06-19

本文共 2781 字,大约阅读时间需要 9 分钟。

.NET中,函数并不是第一级成员,所以并不能像JavaScript那样通过在函数中内嵌子函数的方式实现闭包,通常而言,形成闭包有一些值得总结的非必要条件:

 嵌套定义的函数。

 匿名函数。

 将函数作为参数或返回值。

.NET中,可以通过匿名委托形成闭包:

delegate void MessageDelegate(); static void Main(string[] args){    string value = "Hello, Closure.";     MessageDelegate message = delegate()    {        Show(value);    };     message();} private static void Show(string message){    Console.WriteLine(message);}

  

实上,大部分支持闭包的高级语言中,函数都是第一级成员,函数可以作为参数传递,也可以作为返回值返回,或者作为函数变量。而在.NET中,这一切都可以通过委托来实现,关于委托的详情请参考9.7节“一脉相承:委托、匿名方法和Lambda表达式”,所以上述逻辑也可以通过Lambda表达式实现更简单的代码。

反编译上述示例为IL代码:

.class private auto ansi beforefieldinit Program    extends [mscorlib]System.Object{    .method private hidebysig static void Main(string[] args) cil managed    {        // 省略    }     .class auto ansi sealed nested private beforefieldinit <>c__DisplayClass1        extends [mscorlib]System.Object    {        .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()        .method public hidebysig specialname rtspecialname instance void .ctor() cil managed        {            // 省略        }         .method public hidebysig instance void 
b__0() cil managed { // 省略 } .field public string value }}

  

通过匿名方法将自动形成闭包,自由变量value被包装在一个内部类(闭包)中,并升级为实例成员,即使创建该变量的方法执行结束,该变量也不会释放,而是在所有回调函数执行之后才被GC回收。自由变量value的生命周期被延长,并不局限为一个局部变量。生命周期的延迟,是闭包带来的福利,但是也往往带来潜在的问题,造成更多的消耗。

1.闭包与函数

像对象一样的操作函数,是闭包发挥的最大作用,从而实现了模块化的方式。不过,闭包与函数并不是一回事儿。

 包是函数与其引用环境组合而成的实体。不同的引用环境和相同的函数可以组合产生不同的闭包实例。

 函数是一段可执行的代码体,在运行时不会由于上下文环境发生变化。

2.应用闭包

闭包,是函数式编程的精灵,在.NET平台中,这个精灵同样带来诸多方面的应用,典型的表现主要体现在以下几方面。

 定义控制结构,实现模块化应用。闭包实现了以最简单的方式开发粒度最小的模块应用,实现一定程度的算法复用,下例的ForEach为遍历数组元素提供了复用基础,对于加法运算和减法运算而言,在闭包中改变引用环境变量的值,达到最小粒度的模块控制效果。

static void Main(){    int[] values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};     int result1 = 0;    int result2 = 100;     values.ForEach(x => result1 += x);    values.ForEach(x => result2 -= x);     Console.WriteLine(result1);    Console.WriteLine(result2);}

  

 多个函数共享相同的上下文环境,进而实现通过上下文变量达到数据交流的作用。

static void Main(){    int value = 100;     IList
> funcs = new List
>(); funcs.Add(() => value + 1); funcs.Add(() => value - 2); foreach (var f in funcs) { value = f(); Console.WriteLine(value); }}

  

数据共享为不同函数的操作间传递数据带来方便,但是这把双刃剑有时又为不需要共享数据的场合带来问题,以上例而言,value变量将在不同的操作中() => value + 1() => value – 2间共享数据。如果不希望在两次操作间传递数据,需要特别注意引入中间量协调:

static void Main(){    int value = 100;     IList
> funcs = new List
>(); funcs.Add(() => value + 1); funcs.Add(() => value - 2); foreach (var f in funcs) { int v = f(); Console.WriteLine(v); }}

  

转载地址:http://qfctx.baihongyu.com/

你可能感兴趣的文章
08:石头剪刀布
查看>>
【SAP HANA】新建账户和数据库(2)
查看>>
Rsync服务介绍与配置
查看>>
JQuery获取浏览器窗口的可视区域高度和宽度,滚动条高度
查看>>
CentOS 6.4下编译安装MySQL 5.6.14 (转)
查看>>
在同一台电脑上添加多个ssh key
查看>>
直方图、基数、选择性、群集因子
查看>>
ASP.NET Web API身份验证和授权
查看>>
dbcp 详细配置
查看>>
如何定义StrokeIt手势 常用StrokeIt手势大全
查看>>
LCA 最近公共祖先
查看>>
23种设计模式之工厂方法
查看>>
Docker
查看>>
Java笔记4:JDBC纯驱动方式连接Oracle
查看>>
java 内部类、匿名内部类、嵌套类的使用
查看>>
Scala使用Akka模拟RPC机制代码
查看>>
Linux下使用Fastboot给手机刷ROM
查看>>
怎样在tsung中使用动态參数(二)
查看>>
HDU 1272 小希的迷宫
查看>>
js之iframe子页面与父页面通信
查看>>