成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C#中的閉包是怎么捕獲變量的

開發(fā) 后端
閉包是可以包含自由(未綁定)變量的代碼塊;這些變量不是在這個代碼塊或者任何全局上下文中定義的,而是在定義代碼塊的環(huán)境中定義。本文主要介紹了C#中的閉包是怎么捕獲變量的。

簡單來講,閉包允許你將一些行為封裝,將它像一個對象一樣傳來遞去,而且它依然能夠訪問到原來***次聲明時的上下文。這樣可以使控制結構、邏輯操作等從調用細節(jié)中分離出來。訪問原來上下文的能力是閉包區(qū)別一般對象的重要特征,盡管在實現上只是多了一些編譯器技巧。

我們知道,在匿名方法或者lambda中,可以訪問或者修改該匿的定義范圍內的變量。例如:

  1. int num = 1;   
  2. Func<int> incNum = () => ++num; 

其中l(wèi)ambda表達式使用了在其外部定義的變量num。我們可以認為該段lambda語句塊構成了一個閉包,而這個閉包捕獲了外部變量num。

好了,不說那么多讓人看著難受的定義套話了。我們進入正題,看看在C#中變量是如何被捕獲的。來看一個例子:

  1. public Func<String> CreateFunction()   
  2. {   
  3. String str = "我的幸運數字是";   
  4. int num = 17;   
  5. Func<String> func = () => str + num;   
  6. return func;   

在這個例子中,定義了一個返回一個函數的方法CreateFunction。返回的函數構成了一個閉包,該閉包捕獲了兩個變量:String類型的str和int類型的num。

好了,我們現在可以這樣使用這個函數了:

  1. Func<String>   
  2. myFunc = CreateFunction();   
  3. String result = myFunc();  

我們來分析一下這兩行代碼實際都干了什么。***行很容易理解,我們把方法CreateFunction生成的匿名函數賦值給了委托myFunc。

第二行更好理解,我們執(zhí)行了myFunc,并將返回結果賦值給了變量result。我們再深入思考一下:在執(zhí)行myFunc的時候,會訪問到在CreateFunction中定義兩個變量str與num。

雖然這時CreateFunction的棧幀早就被銷毀了,其內部定義的變量至今也“生死不明”了,但是因為我們知道這兩個變量已經被閉包所捕獲了,所以我們堅信這兩個變量截至目前為止還是可以訪問的!

對于str對象,鑒于它是一個引用類型,所以只要有存在某個“東西”一直保存著對它的引用,它就不會被銷毀。這樣我們完全不用擔心在我們需要它時,編譯器或運行時會告訴我們它被弄丟了。

然而對于num,情況就有些不同了。num是一個值類型。我們知道值類型是存活在棧上的,我們也知道它所存在的那個棧幀(也就是CreateFunction的幀)在CreateFunction執(zhí)行完畢后就會被銷毀,然后其上存在的任何值類型也會被一并的銷毀,這其中當然包括我們所關注的變量num了。

那么,我們?yōu)槭裁催€能安全的訪問num呢?C#中的變量捕獲機制究竟有什么神奇之處,可以讓值類型擁有違反常規(guī)的生存周期呢?裝箱!你可能會立刻想到,把每個值類型都裝到一個對象里,我們就可以讓這個值類型擁有和那個包裹它的對象相同的壽命了。

不過,這并不是C#實現者所選擇的方式!C#并不會對每個需要捕獲的值類型變量進行裝箱操作,而是把所有捕獲的變量統(tǒng)統(tǒng)放到同一個大“箱子”里——當編譯器遇到需要變量捕獲的情況時,它會默默地在后臺構造一個類型,這個類型包含了每一個閉包所捕獲的變量(包括值類型變量和引用類型變量)作為它的一個公有字段。這樣,編譯器就可以

維護那些在匿名函數或lambda表達式中出現的外部變量了。

更進一步,如果我們使用ILDASM工具查看CreateFunction方法的IL代碼,我們會發(fā)現編譯器壓根就沒有聲明num和str變量。取而代之的是聲明了一個類型名和實例名都及其難看的包裝對象。這個玩意兒就是我們上面所說的那個被編譯器默默生成,保存了所有捕獲變量的引用的對象。

我們還可以看到,在CreateFunction方法,C#源代碼內所有對str和num的操作,在IL中都被轉換成了對包裝對象的同名公有成員的操作。順便說一句,就連我們構造的那個lambda表達式“() => str + num”現在都被編譯器轉換成了這個包裝對象的一個方法!

【編輯推薦】

  1. 使用ASP.NET操作IIS7中使用應用程序
  2. SqlParameter的作用與用法
  3. ASP.net的身份驗證方式FORMS
  4. C#使用MemoryStream類讀寫內存
  5. C#控件的閃爍問題解決方法總結
責任編輯:于鐵 來源: 博客園
相關推薦

2011-08-05 09:33:30

Func局部變量作用域

2023-09-11 08:20:17

對象閉包底層

2021-10-26 13:18:52

Go底層函數

2022-06-08 08:01:20

useEffect數組函數

2024-11-26 00:45:29

free區(qū)域字段

2024-01-08 08:35:28

閉包陷阱ReactHooks

2024-03-11 16:13:26

C#編程開發(fā)

2025-04-29 10:30:00

C++Lambda函數

2019-11-07 21:51:18

閉包前端函數

2012-11-29 10:09:23

Javascript閉包

2016-11-01 09:18:33

Python閉包

2020-05-28 15:41:48

微軟C+語言

2023-11-02 08:53:26

閉包Python

2022-05-30 16:19:26

C#多態(tài)底層虛方法

2024-01-22 09:51:32

Swift閉包表達式尾隨閉包

2011-05-12 18:26:08

Javascript作用域

2009-07-31 18:39:31

C#中foreach引

2009-07-22 07:43:00

Scala閉包

2023-01-09 08:00:41

JavaScript閉包

2020-12-16 11:09:27

JavaScript語言開發(fā)
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 在线观看中文字幕一区二区 | 国产精品视频不卡 | 中文字幕一区二区三区精彩视频 | 亚洲欧美在线视频 | 一区二区精品视频 | 国产丝袜一区二区三区免费视频 | a级网站 | www日本在线观看 | 日韩一区二区av | 自拍偷拍亚洲欧美 | 久久久久久久久国产成人免费 | 国产成人精品免费视频大全最热 | 久久精品视频一区二区 | 99re视频在线观看 | 1000部精品久久久久久久久 | 国产成人av在线播放 | www.日日夜夜 | 精品在线一区 | 久久亚洲一区二区三区四区 | 在线观看亚洲专区 | 毛片免费视频 | 亚洲毛片 | 偷派自拍 | 国产日韩视频 | 国产精品海角社区在线观看 | 国产成人精品免高潮在线观看 | 久久成人精品视频 | 欧美日韩在线精品 | 91成人 | 91九色视频 | 欧美日韩视频在线第一区 | 国产精品第2页 | 国产精品久久影院 | 久久精品国产一区 | 国产精品欧美一区二区 | 日本不卡一区二区三区在线观看 | 色综合欧美| 91久久精品国产91久久 | 免费永久av | 日韩中文字幕在线观看 | 亚洲成人av一区二区 |