九九热这里直有精品,1区二区三区在线播放,玖玖爱在线观看资源,国产aⅴ综合网,午夜福利男女,日本亚洲欧美三级,日韩无码黄色导航,内射少妇13区,中文字幕高清网

您身邊的軟件定制專家--9年開發(fā)經(jīng)驗為您護航

18678812288
0531-88887250

C#函數(shù)式程序設(shè)計之用閉包封裝數(shù)據(jù)

文章作者:濟南軟件開發(fā) 時間:2016年11月08日

  如果一個程序設(shè)計語言能夠用高階函數(shù)解決問題,則意味著數(shù)據(jù)作用域問題已十分突出。當函數(shù)可以當成參數(shù)和返回值在函數(shù)之間進行傳遞時,編譯器利用閉包擴展變量的作用域,以保證隨時能得到所需要的數(shù)據(jù)。

  C#函數(shù)式程序設(shè)計之作用域

  在C#中,變量的作用域是嚴格確定的。其本質(zhì)是所有代碼生存在類的方法中、所有變量只生存于聲明它們的模塊中或者之后的代碼中。變量的值是可變的,一個變量越是公開,帶來的問題就越嚴重。一般的原則是,變量的值最好保持不變,或者在最小的作用域內(nèi)保存其值。一個純函數(shù)最好只使用在自己的模塊中定義的變量值,不訪問其作用域之外的任何變量。

  遺憾的是,有時我們無法把變量的值限制于函數(shù)的范圍內(nèi)。如果在程序的初始化時定義了幾個變量,在后面需要反復(fù)用到它們,怎么辦?一個可能的辦法是使用閉包。

  C#函數(shù)式程序設(shè)計之閉包機制

  為了理解閉包的本質(zhì),我們分析幾個使用閉包的例子:

  namespace Closures

  {

  class Closures

  {

  static void Closures()

  {

  Console.WriteLine(GetClosureFunc()(30));

  }

  static Func<int,int> GetClosureFunc()

  {

  int val = 10;

  Func<int, int> internalAdd = x => x + val;

  Console.WriteLine(internalAdd(10));

  val = 30;

  Console.WriteLine(internalAdd(10));

  return internalAdd;

  }

  }

  }

  此代碼的結(jié)果輸出是多少?答案是20  40  60,前面兩個值,大家應(yīng)該很容易就能看出來,但第三個值為什么是60呢?先來看看程序的執(zhí)行流程:Closures函數(shù)調(diào)用GetClosureFunc函數(shù)并進入其中。函數(shù)調(diào)用語句中帶了一個參數(shù)30。這是由于GetClosureFunc返回的是一個函數(shù),即執(zhí)行時再次調(diào)用了這個函數(shù),進入GetClosureFunc函數(shù)中,首先val的值為10,通過internalAdd方法傳入一個值10,因此第一個輸出值為20,往下走,val的值變成30,通過internalAdd方法傳入值10,于是第二個輸出值為40。從這里我們大致可以看出,局部函數(shù)和局部變量如何在同一個作用域中起作用,顯然,對局部變量的改變會影響internalAdd的值,盡管變量的改變發(fā)生在internalAdd最初的創(chuàng)建之后。最后,GetClosureFunc返回了internalAdd方法,以參數(shù)30再次調(diào)用這個函數(shù),于是,結(jié)果成為60。

  初看起來,這并不真正符合邏輯。val應(yīng)該是一個局部變量,它生存在棧中,當GetClosureFunc函數(shù)返回時,它就不在了,不是么?確實如此,這正是閉包的目的,當編譯器會明白無誤地警告這種情況會引起程序的崩潰時阻止變量值超出其作用域之外。

  從技術(shù)角度來看,數(shù)據(jù)保存的位置很重要,編譯器創(chuàng)建一個匿名類,并在GetClosureFunc中創(chuàng)建這個類的實例——如果不需要閉包起作用,則那個匿名函數(shù)只會與GetClosureFunc生存在同一個類中,最后,局部變量val實際上不再是一個局部變量,而是匿名類中的一個字段。其結(jié)果是,internalAdd現(xiàn)在可以引用保存在匿名類實例中的函數(shù)。這個實例中也包含變量val的數(shù)據(jù)。只要保持internalAdd的引用,變量val的值就一直保存著。

  下面這段代碼說明編譯器在這種情形下采用的模式:

  private sealed class DisplayClass

  {

  public int val;

  public int AnonymousFunc(int x)

  {

  return x + this.val;

  }

  private static Func<int, int> GetClosureFunc()

  {

  DisplayClass displayClass = new DisplayClass();

  displayClass.val = 10;

  Func<int, int> internalAdd = displayClass.AnonymousFunc;

  Console.WriteLine(internalAdd(10));

  displayClass.val = 30;

  Console.WriteLine(internalAdd(10));

  return internalAdd;

  }

  }

  回到動態(tài)創(chuàng)建函數(shù)思想:現(xiàn)在可以憑空創(chuàng)建新的函數(shù),而且它的功能因參數(shù)而異。例如,下面這個函數(shù)把一個靜態(tài)值加到一個參數(shù)上:

  private static void DynamicAdd()

  {

  var add5 = GetAddX(5);

  var add10 = GetAddX(10);

  Console.WriteLine(add5(10));

  Console.WriteLine(add10(10));

  }

  private static Func<int,int> GetAddX(int staticVal)

  {

  return x => staticVal + x;

  }

  這個原理正是許多函數(shù)構(gòu)建技術(shù)的基礎(chǔ),這種方法顯然與方法重載等面向?qū)ο蠓椒ㄏ鄬?yīng)。但是與方法重載不同,匿名函數(shù)的創(chuàng)建可以在運行時動態(tài)發(fā)生,只需受另一個函數(shù)中的一行代碼觸發(fā)。為使某個算法更加容易讀和寫而使用的特殊函數(shù)可以在調(diào)用它的方法中創(chuàng)建,而不是再類級別上胡亂添加函數(shù)或方法——這正是函數(shù)模塊化的核心思想。


想要了解更多詳情歡迎來電咨詢18678812288
登陸網(wǎng)址:m.h6244.cn。
聯(lián)系人:王經(jīng)理。

井研县| 兴国县| 高尔夫| 浮山县| 咸丰县| 安西县| 武山县| 恩平市| 洞口县| 红原县| 中阳县| 建宁县| 南开区| 邯郸市| 喀喇| 东港市| 星座| 三江| 涡阳县| 新蔡县| 平顺县| 瓦房店市| 天柱县| 广丰县| 大安市| 宣恩县| 桂林市| 梓潼县| 海伦市| 西畴县| 大名县| 泗水县| 扶沟县| 裕民县| 长武县| 榕江县| 光泽县| 淮北市| 株洲县| 万载县| 乐都县|