最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#函數(shù)式程序設(shè)計(jì)之用閉包封裝數(shù)據(jù)的實(shí)現(xiàn)代碼

 更新時(shí)間:2014年03月19日 15:08:12   作者:  
如果一個(gè)程序設(shè)計(jì)語(yǔ)言能夠用高階函數(shù)解決問題,則意味著數(shù)據(jù)作用域問題已十分突出。當(dāng)函數(shù)可以當(dāng)成參數(shù)和返回值在函數(shù)之間進(jìn)行傳遞時(shí),編譯器利用閉包擴(kuò)展變量的作用域,以保證隨時(shí)能得到所需要的數(shù)據(jù)

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

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

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

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

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

復(fù)制代碼 代碼如下:

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

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

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

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

復(fù)制代碼 代碼如下:

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;
    }
}

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

復(fù)制代碼 代碼如下:

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;
}

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

總結(jié)

閉包是程序設(shè)計(jì)語(yǔ)言支持函數(shù)式設(shè)計(jì)方法的一個(gè)重要工具。

相關(guān)文章

  • C#中幾個(gè)未知的Visual Studio編碼技巧分享

    C#中幾個(gè)未知的Visual Studio編碼技巧分享

    用了多年的Visual Studio,今天才發(fā)現(xiàn)這個(gè)編碼技巧,真是慚愧,分享出來,算是拋磚引玉吧,需要的朋友可以參考下
    2012-11-11
  • C#中參數(shù)數(shù)組、引用參數(shù)和輸出參數(shù)示例詳解

    C#中參數(shù)數(shù)組、引用參數(shù)和輸出參數(shù)示例詳解

    這篇文章主要給大家介紹了關(guān)于C#中參數(shù)數(shù)組、引用參數(shù)和輸出參數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05
  • c# base關(guān)鍵字的具體使用

    c# base關(guān)鍵字的具體使用

    base關(guān)鍵字用于從派生類中訪問基類的成員,本文主要介紹了c# base關(guān)鍵字的具體使用,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-03-03
  • C#使用HttpHelper框架重啟路由器

    C#使用HttpHelper框架重啟路由器

    這篇文章介紹了C#使用HttpHelper框架重啟路由器的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • 淺析C# web訪問mysql數(shù)據(jù)庫(kù)-整理歸納總結(jié)

    淺析C# web訪問mysql數(shù)據(jù)庫(kù)-整理歸納總結(jié)

    本篇文章是對(duì)C#中的web訪問mysql數(shù)據(jù)庫(kù)的一些知識(shí)點(diǎn)進(jìn)行了整理歸納總結(jié),需要的朋友可以參考下
    2013-07-07
  • c#判斷正確的ip地址格式示例

    c#判斷正確的ip地址格式示例

    這篇文章主要介紹了c#判斷正確的ip地址格式示例,需要的朋友可以參考下
    2014-02-02
  • C#自定義基于控制臺(tái)的Timer實(shí)例

    C#自定義基于控制臺(tái)的Timer實(shí)例

    這篇文章主要介紹了C#自定義基于控制臺(tái)的Timer實(shí)現(xiàn)方法,可以簡(jiǎn)單模擬timer控件的相關(guān)功能,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-08-08
  • C#使用默認(rèn)瀏覽器打開網(wǎng)頁(yè)的方法

    C#使用默認(rèn)瀏覽器打開網(wǎng)頁(yè)的方法

    這篇文章主要介紹了C#使用默認(rèn)瀏覽器打開網(wǎng)頁(yè)的方法,涉及C#操作瀏覽器屬性的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • C#中實(shí)現(xiàn)抽象類里建立靜態(tài)方法

    C#中實(shí)現(xiàn)抽象類里建立靜態(tài)方法

    這篇文章主要介紹了C#中實(shí)現(xiàn)抽象類里建立靜態(tài)方法,需要的朋友可以參考下
    2014-07-07
  • SQLite在C#中的安裝與操作技巧

    SQLite在C#中的安裝與操作技巧

    SQLite,是一款輕型的數(shù)據(jù)庫(kù),用于本地的數(shù)據(jù)儲(chǔ)存。其優(yōu)點(diǎn)有很多,下面通過本文給大家介紹SQLite在C#中的安裝與操作技巧,感興趣的的朋友參考下吧
    2017-08-08

最新評(píng)論

祁东县| 页游| 柘城县| 苏尼特右旗| 高安市| 乌拉特前旗| 定襄县| 滨州市| 紫云| 镶黄旗| 成都市| 阳西县| 陇川县| 博罗县| 阳江市| 贡山| 固安县| 湖州市| 理塘县| 乌苏市| 山阴县| 佛冈县| 永吉县| 阜新| 怀柔区| 博客| 鹰潭市| 周宁县| 兰州市| 十堰市| 安西县| 台湾省| 定西市| 东乌| 吉木萨尔县| 霞浦县| 大埔区| 遂溪县| 新郑市| 阿图什市| 平顺县|