当前位置:编程学习 > asp >>

.NET也有闭包

在.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.CompilerGenerated Attribute::.ctor()
  .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
  {
  // 省略
  }
  .method public hidebysig instance void <Main>b__0() cil managed
  {
  // 省略
  }
  .field public string value
  }
  }
[NextPage]
  通过匿名方法将自动形成闭包,自由变量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<Func<int>> funcs = new List<Func<int>>();
  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<Func<int>> funcs = new List<Func<int>>();
  funcs.Add(() => value + 1);
  funcs.Add(() => value - 2);
  foreach (var f in funcs)
  {
  int v = f();
  Console.WriteLine(v);
  }
  }

补充:Web开发 , ASP.Net ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,