精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

C#語法糖 聊聊閉包的底層玩法

開發(fā) 前端
捕獲是一個(gè)很抽象?的詞,一點(diǎn)都不接底氣,這里我用 面向?qū)ο? 的角度來解讀一下,這個(gè)問題本質(zhì)上就是 棧變量? 和 堆變量 混在一起的一次行為沖突,什么意思呢?

有朋友好奇為什么將 閉包 歸于語法糖,這里簡單聲明下,C# 中的所有閉包最終都會(huì)歸結(jié)于 類 和 方法,為什么這么說,因?yàn)?C# 的基因就已經(jīng)決定了,如果大家了解 CLR 的話應(yīng)該知道, C#中的類最終都會(huì)用 MethodTable 來承載,方法都會(huì)用 MethodDesc 來承載, 所以不管你怎么玩都逃不出這三界之內(nèi)。

這篇我們就來聊聊C#中的閉包底層原理及玩法,表面上的概念就不說了哈。

一:普通閉包玩法

1. 案例演示

放了方便說明,先上一段測(cè)試代碼:

static void Main(string[] args)
        {
            int y = 10;

            Func<int, int> sum = x =>
            {
                return x + y;
            };

            Console.WriteLine(sum(11));
        }

剛才也說了,C#的基因決定了最終會(huì)用 class 和 method 對(duì) 閉包 進(jìn)行面向?qū)ο蟾脑欤侨绾胃脑炷兀窟@里有兩個(gè)問題:

  • 匿名方法如何面向?qū)ο蟾脑?/li>

方法 不能脫離 類 而獨(dú)立存在,所以 編譯器 必須要為其生成一個(gè)類,然后再給匿名方法配一個(gè)名字即可。

  • 捕獲到的 y 怎么辦

捕獲是一個(gè)很抽象的詞,一點(diǎn)都不接底氣,這里我用 面向?qū)ο?nbsp;的角度來解讀一下,這個(gè)問題本質(zhì)上就是 棧變量 和 堆變量 混在一起的一次行為沖突,什么意思呢?

  1. 棧變量

大家應(yīng)該知道 棧變量 所在的幀空間是由 esp 和 ebp 進(jìn)行控制,一旦方法結(jié)束,esp 會(huì)往回收縮造成局部變量從棧中移除。

  1. 堆變量

委托是一個(gè)引用類型,它是由 GC 進(jìn)行管理回收,只要它還被人牽著,自然就不會(huì)被回收。

到這里我相信你肯定發(fā)現(xiàn)了一個(gè)嚴(yán)重的問題, 一旦 sum 委托逃出了方法,這時(shí)局部變量 y 肯定會(huì)被銷毀,如果真的被銷毀了, 后續(xù)再執(zhí)行 sum 委托自然就是一個(gè)巨大的bug,那怎么辦呢?

編譯器自然早就考慮到了這種情況,它在進(jìn)行面向?qū)ο蟾脑斓臅r(shí)候,特意為 類 定義了一個(gè) public 類型的字段,用這個(gè)字段來承載這個(gè)局部變量。

2. 手工改造

有了這些多前置知識(shí),我相信你肯定會(huì)知道如何改造了,參考代碼如下:

class Program
    {
        static void Main(string[] args)
        {
            int y = 10;

            //Func<int, int> sum = x =>
            //{
            //    return x + y;
            //};

            //面向?qū)ο蟾脑?            FuncClass funcClass = new FuncClass() { y = y };

            Func<int, int> sum = funcClass.Run;

            Console.WriteLine(sum(11));
        }
    }

    public class FuncClass
    {
        public int y;

        public int Run(int x)
        {
            return x + y;
        }
    }

如果你不相信的話,可以看下 MSIL 代碼。

.method private hidebysig static 
 void Main (
  string[] args
 ) cil managed 
{
 // Method begins at RVA 0x2050
 // Code size 43 (0x2b)
 .maxstack 2
 .entrypoint
 .locals init (
  [0] class ConsoleApp1.Program/'<>c__DisplayClass0_0' 'CS$<>8__locals0',
  [1] class [System.Runtime]System.Func`2<int32, int32> sum
 )

 IL_0000: newobj instance void ConsoleApp1.Program/'<>c__DisplayClass0_0'::.ctor()
 IL_0005: stloc.0
 IL_0006: nop
 IL_0007: ldloc.0
 IL_0008: ldc.i4.s 10
 IL_000a: stfld int32 ConsoleApp1.Program/'<>c__DisplayClass0_0'::y
 IL_000f: ldloc.0
 IL_0010: ldftn instance int32 ConsoleApp1.Program/'<>c__DisplayClass0_0'::'<Main>b__0'(int32)
 IL_0016: newobj instance void class [System.Runtime]System.Func`2<int32, int32>::.ctor(object, native int)
 IL_001b: stloc.1
 IL_001c: ldloc.1
 IL_001d: ldc.i4.s 11
 IL_001f: callvirt instance !1 class [System.Runtime]System.Func`2<int32, int32>::Invoke(!0)
 IL_0024: call void [System.Console]System.Console::WriteLine(int32)
 IL_0029: nop
 IL_002a: ret
} // end of method Program::Main


.class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass0_0'
 extends [System.Runtime]System.Object
{
 .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
  01 00 00 00
 )
 // Fields
 .field public int32 y

 // Methods
 .method public hidebysig specialname rtspecialname 
  instance void .ctor () cil managed 
 {
  // Method begins at RVA 0x2090
  // Code size 8 (0x8)
  .maxstack 8

  IL_0000: ldarg.0
  IL_0001: call instance void [System.Runtime]System.Object::.ctor()
  IL_0006: nop
  IL_0007: ret
 } // end of method '<>c__DisplayClass0_0'::.ctor

 .method assembly hidebysig 
  instance int32 '<Main>b__0' (
   int32 x
  ) cil managed 
 {
  // Method begins at RVA 0x209c
  // Code size 14 (0xe)
  .maxstack 2
  .locals init (
   [0] int32
  )

  IL_0000: nop
  IL_0001: ldarg.1
  IL_0002: ldarg.0
  IL_0003: ldfld int32 ConsoleApp1.Program/'<>c__DisplayClass0_0'::y
  IL_0008: add
  IL_0009: stloc.0
  IL_000a: br.s IL_000c

  IL_000c: ldloc.0
  IL_000d: ret
 } // end of method '<>c__DisplayClass0_0'::'<Main>b__0'

} // end of class <>c__DisplayClass0_0

二:循環(huán)下閉包玩法

為了方便說明,還是先上一段代碼。

static void Main(string[] args)
        {
            var actions = new Action[10];

            for (int i = 0; i < actions.Length; i++)
            {
                actions[i] = () => Console.WriteLine(i);
            }

            foreach (var item in actions) item();
        }

然后把代碼跑起來:

我相信有非常多的朋友都踩過這個(gè)坑,那為什么會(huì)出現(xiàn)這樣的結(jié)果呢?我試著從原理上解讀一下。

1. 原理解讀

根據(jù)前面所學(xué)的 面向?qū)ο?nbsp;改造法,我相信大家肯定會(huì)很快改造出來,參考代碼如下:

class Program
    {
        static void Main(string[] args)
        {
            var actions = new Action[10];

            for (int i = 0; i < actions.Length; i++)
            {
                //actions[i] = () => Console.WriteLine(i);

                //改造后
                var funcClass = new FuncClass() { i = i };
                actions[i] = funcClass.Run;
            }

            foreach (var item in actions) item();
        }
    }

    public class FuncClass
    {
        public int i;

        public void Run()
        {
            Console.WriteLine(i);
        }
    }

然后跑一下結(jié)果:

真奇葩,我們的改造方案一點(diǎn)問題都沒有,咋 編譯器 就弄不對(duì)呢?要想找到案例,只能看 MSIL 啦,簡化后如下:

IL_0001: ldc.i4.s 10
  IL_0003: newarr [System.Runtime]System.Action
  IL_0008: stloc.0
  IL_0009: newobj instance void ConsoleApp1.Program/'<>c__DisplayClass0_0'::.ctor()
  IL_000e: stloc.1
  IL_000f: ldloc.1
  IL_0010: ldc.i4.0
  IL_0011: stfld int32 ConsoleApp1.Program/'<>c__DisplayClass0_0'::i
  IL_0016: br.s IL_003e
  // loop start (head: IL_003e)
   IL_0018: nop
   IL_0019: ldloc.0
            ...
  // end loop

如果有興趣大家可以看下完整版,它的實(shí)現(xiàn)方式大概是這樣的。

static void Main(string[] args)
        {
            var actions = new Action[10];

            var funcClass = new FuncClass();

            for (int i = 0; i < actions.Length; i++)
            {
                actions[i] = funcClass.Run;

                funcClass.i = i + 1;
            }

            foreach (var item in actions) item();
        }

原來問題就出在了它只 new 了一次,同時(shí) for 循環(huán)中只是對(duì)  i 進(jìn)行了賦值,導(dǎo)致了問題的發(fā)生。

2. 編譯器的想法

為什么編譯器會(huì)這么改造代碼,我覺得可能基于下面兩點(diǎn)。

  • 不想 new 太多的類實(shí)例

new一個(gè)對(duì)象,其實(shí)并沒有大家想象的那么簡單,在 clr 內(nèi)部會(huì)分 快速路徑 和 慢速路徑,同時(shí)還為此導(dǎo)致 GC 回收,為了保存一個(gè)變量 需要專門 new 一個(gè)實(shí)例,這代價(jià)真的太大了。。。

  • 有更好的解決辦法

更好的辦法就是用 方法參數(shù) ,方法的字節(jié)碼是放置在 CLR 的 codeheap 上,獨(dú)此一份,同時(shí)方法參數(shù)只是在棧上多了一個(gè)存儲(chǔ)空間而已,這代價(jià)就非常小了。

三:代碼改造

知道編譯器的苦衷后,改造起來就很簡單了,大概有如下兩種。

1. 強(qiáng)制 new 實(shí)例

這種改造法就是強(qiáng)制在每次 for 中 new 一個(gè)實(shí)例來承載 i 變量,參考代碼如下:

static void Main(string[] args)
        {
            var actions = new Action[10];

            for (int i = 0; i < actions.Length; i++)
            {
                var j = i;
                actions[i] = () => Console.WriteLine(j);
            }

            foreach (var item in actions) item();
        }

2. 采用方法參數(shù)

為了能夠讓 i 作為方法參數(shù),只能將 Action 改成 Action<int>,雖然你可能要為此掉頭發(fā),但對(duì)程序性能來說是巨大的,參考代碼如下:

static void Main(string[] args)
        {
            var actions = new Action<int>[10];

            for (int i = 0; i < actions.Length; i++)
            {
                actions[i] = (j) => Console.WriteLine(j);
            }

            for (int i = 0; i < actions.Length; i++)
            {
                actions[i](i);
            }
        }

好了,洋洋灑灑寫了這么多,希望對(duì)大家有幫助。

責(zé)任編輯:武曉燕 來源: 一線碼農(nóng)聊技術(shù)
相關(guān)推薦

2023-09-01 10:00:17

2011-08-05 09:33:30

Func局部變量作用域

2011-05-23 13:54:04

閉包

2021-10-26 13:18:52

Go底層函數(shù)

2025-01-10 08:15:22

C#異步底層

2009-05-13 14:15:09

PHP 5.3閉包匿名函數(shù)

2022-05-30 16:19:26

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

2009-11-23 14:17:50

PHP 5.3閉包語法

2016-06-02 15:10:12

SwiftSelector

2020-12-08 07:51:53

Java語法糖泛型

2009-08-19 15:38:59

C#代碼

2022-02-14 08:04:02

Go語法糖編譯器

2021-01-30 11:12:21

C#List數(shù)據(jù)

2024-10-21 16:59:37

C#編程多線程

2024-05-15 09:11:51

委托事件C#

2009-08-27 11:43:31

C#語法

2025-04-08 00:07:37

語法糖C#代碼

2023-10-09 07:11:03

排序算法序列

2024-09-29 09:28:38

Action?C#

2024-01-22 09:51:32

Swift閉包表達(dá)式尾隨閉包
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

91精品国产91久久| 亚洲免费成人av电影| 亚洲中文字幕无码一区二区三区| jizz中国女人| 久久精选视频| 欧美人交a欧美精品| 超碰97在线资源站| 亚洲欧美久久精品| 黑人与娇小精品av专区| 久久精品国产精品亚洲精品色| 亚洲国产中文字幕在线| 日韩和的一区二区| 久久久久久国产精品三级玉女聊斋| 97伦伦午夜电影理伦片| 精品精品视频| 在线亚洲免费视频| 免费看毛片的网址| 免费a在线看| 久久久久久久电影| 国产精品区二区三区日本| 中文在线免费看视频| 亚洲经典在线| 主播福利视频一区| 日韩中文字幕有码| 亚洲深夜福利在线观看| 日韩免费一区二区| 永久免费的av网站| 欧美日韩视频免费观看| 精品久久久久久久久久久久久久 | 国产精品一区二区人妻喷水| 欧美性生活一级| 91成人免费在线| 妞干网在线视频观看| 午夜av在线播放| 亚洲丝袜美腿综合| 一区二区在线观看网站| 激情小说 在线视频| 不卡的av中国片| 成人动漫在线观看视频| av 一区二区三区| 久久狠狠亚洲综合| 国产精品视频公开费视频| 亚洲av无码不卡| 久久国产免费| 91av中文字幕| 亚洲精品中文字幕乱码三区91| 亚洲高清电影| 97在线视频观看| 麻豆精品一区二区三区视频| 欧美影院一区| 久久国产精品99国产精| 久久久久久视频| 久久久久亚洲| 色在人av网站天堂精品| 妺妺窝人体色www聚色窝仙踪| 亚洲情侣在线| 欧美日韩成人在线视频| 国产亚洲精品av| 亚洲福利精品| 日韩美女福利视频| 丰满人妻一区二区三区四区| 日本aⅴ精品一区二区三区| 国产精品9999| 国产精品伊人久久| 国产成人在线视频播放| 国产欧美一区二区在线播放| 天堂在线视频免费| 91亚洲永久精品| 欧洲一区二区在线| 久做在线视频免费观看| 亚洲综合另类小说| 国产最新免费视频| 视频一区在线免费看| 欧美片网站yy| 在线播放av网址| 亚洲区小说区| 日韩网站免费观看高清| 久久久香蕉视频| 香蕉久久a毛片| 国产日韩在线看片| 亚洲欧美激情在线观看| 91免费观看视频| 亚洲日本精品一区| 韩国成人免费视频| 日本乱人伦aⅴ精品| 欧美日韩精品区别| 国内精品麻豆美女在线播放视频 | 在线观看a级片| 丁香五六月婷婷久久激情| 成人午夜激情av| 中文字幕久久精品一区二区| 亚洲美女动态图120秒| 天天鲁一鲁摸一摸爽一爽| 亚洲国产专区| 国产欧美日韩中文字幕在线| 欧美一区二区三区成人片在线| 91麻豆国产自产在线观看| 樱花www成人免费视频| 国产精品一二三产区| 欧美日韩免费不卡视频一区二区三区 | 美国一区二区三区在线播放| 99久久综合狠狠综合久久止| 国产精品视频一区二区久久| 香港成人在线视频| 中文字幕久久av| 亚洲欧洲色图| 欧美高清在线观看| 亚洲天堂中文网| 91热门视频在线观看| 一级性生活视频| 成人自拍视频网| 亚洲国产精品小视频| 日韩在线中文字幕视频| 久久精品主播| 久久国产手机看片| 神马午夜伦理不卡| 欧美精品久久天天躁| 久久久久久九九九九九| 精久久久久久| 91久久极品少妇xxxxⅹ软件| 91亚洲精选| 色婷婷av一区| 久久人人爽人人人人片| 亚洲视频中文| 99国产盗摄| 最新av在线播放| 欧美精品乱码久久久久久| 欧美丰满老妇熟乱xxxxyyy| 亚洲精品欧美| 精品欧美一区二区久久久伦| 美女精品视频| 日韩视频在线永久播放| 欧美一级片在线视频| 久久成人麻豆午夜电影| 亚洲日本理论电影| 欧美成人福利| 少妇久久久久久| 中文字幕自拍偷拍| 亚洲国产经典视频| 日本人69视频| 亚洲九九视频| 亚洲自拍欧美另类| 亚洲夜夜综合| 欧美岛国在线观看| 精品小视频在线观看| 粉嫩高潮美女一区二区三区 | 成人女同在线观看| 亚洲福利视频免费观看| 日本一级淫片免费放| 97精品久久久午夜一区二区三区 | 在线亚洲人成| 亚洲深夜福利在线| 婷婷激情五月综合| 中文字幕中文字幕一区二区| 在线免费观看av网| 欧美日韩国产欧| 国产专区一区二区三区| 五月天av在线| 中文字幕亚洲一区二区三区| 亚洲无码久久久久| 亚洲美女淫视频| 国产精品果冻传媒| 久久xxxx精品视频| 亚洲永久一区二区三区在线| 国产亚洲字幕| 久久人人看视频| 欧美视频免费一区二区三区| 欧美色图12p| 劲爆欧美第一页| 97se亚洲国产综合在线| 国产精品视频黄色| 亚洲精品tv久久久久久久久久| 99中文字幕| 中文在线а√天堂| www.久久久久久.com| 成人av无码一区二区三区| 精品久久久久久中文字幕一区奶水 | 国产精品一区二区黑人巨大| 亚洲成av人片一区二区梦乃| 国产亚洲精品熟女国产成人| 国精产品一区一区三区mba视频 | 国产婷婷97碰碰久久人人蜜臀 | 国产精欧美一区二区三区蓝颜男同| 中文字幕不卡在线视频极品| 午夜精品久久久久久久96蜜桃 | 国产精品久久久久久久久搜平片| 操人视频免费看| 久久三级视频| 久久久成人精品一区二区三区| 国产精品一线| 国产精品直播网红| аⅴ资源天堂资源库在线| 中文字幕亚洲字幕| 天天操天天操天天操| 欧美福利电影网| 韩国av中文字幕| 亚洲美女屁股眼交| 97人妻人人揉人人躁人人| 国产高清久久久久| 韩国视频一区二区三区| 日韩网站在线| 麻豆一区二区三区在线观看| 国际精品欧美精品| 国产伦视频一区二区三区| 精品三级在线| 欧美一级大片视频| 亚洲男同gay网站| 中文字幕精品久久久久| 天天色棕合合合合合合合| 日韩一区二区免费在线电影| 免费视频网站在线观看入口| 亚洲成av人片一区二区| 好吊色视频在线观看| 国产精品欧美精品| 中文字幕网站在线观看| 91在线视频在线| 在线中文字日产幕| 国产在线乱码一区二区三区| 中文字幕第36页| 久久国产88| 人人妻人人添人人爽欧美一区| 亚洲免费二区| 中文字幕在线乱| 欧美黄色大片在线观看| 日韩欧美精品一区二区三区经典 | 9999在线观看| 日本不卡二三区| 日韩欧美三级一区二区| 国产精品一国产精品| 欧美在线一区二区三区四区| 日韩电影不卡一区| 国产在线资源一区| 九色丨蝌蚪丨成人| 国产精品视频一区二区三区经| 久久综合给合| 97中文在线观看| 亚洲视频精选| 99精品国产高清在线观看| 日本成人精品| 91久久精品国产91久久性色tv | 欧美男体视频| 国产精品成人品| 深夜视频一区二区| 国产精品久久一区主播| 日本免费成人| 亚洲a一级视频| 一区二区三区四区精品视频| 国产精品 日韩| 四虎影视精品| 四虎影院一区二区三区| 色偷偷综合网| 成人免费看片视频在线观看| 欧美视频日韩| 2022亚洲天堂| 另类人妖一区二区av| 一级片免费在线观看视频| 国产精品综合视频| 中国一级特黄录像播放| 久久久久久久久久电影| 成年人视频软件| 日韩毛片在线免费观看| 久久久精品一区二区涩爱| 亚洲va韩国va欧美va| 日本熟女毛茸茸| 欧美人与禽zozo性伦| 国产视频在线一区| 亚洲丁香久久久| 国产在线一二三区| 久久国产精品99国产精| 欧美伦理91| 国产精品自拍偷拍视频| 中文字幕视频精品一区二区三区| 精品国产乱码一区二区三区四区| 自拍自偷一区二区三区| 一区二区不卡在线观看| 亚洲一级电影| 无码内射中文字幕岛国片| 国产最新精品精品你懂的| 亚洲图片综合网| 国产精品嫩草影院com| 欧美激情一区二区视频| 色综合久久综合中文综合网| 97超碰人人模人人人爽人人爱| 精品国产青草久久久久福利| 精品无人乱码| 久久91亚洲精品中文字幕| 欧美性suv| 97人人澡人人爽| 不卡中文一二三区| 国产二区视频在线| 久久91精品久久久久久秒播| www国产视频| 亚洲精品综合在线| 国产字幕在线观看| 精品国产伦一区二区三区观看体验 | 可以免费观看av毛片| 国产盗摄女厕一区二区三区| 99久久久无码国产精品衣服| 亚洲网友自拍偷拍| 艳妇乳肉豪妇荡乳av| 亚洲精品ady| 羞羞的视频在线看| 国产欧美欧洲在线观看| 日本一区福利在线| 成人在线观看毛片| 久久99久久久久久久久久久| 亚洲成人网在线播放| 亚洲国产欧美在线人成| 国产精品亚洲lv粉色| 中日韩美女免费视频网站在线观看 | 国产精品视频大全| 嫩草一区二区三区| 女人天堂av手机在线| 国产成人亚洲精品青草天美| 午夜激情福利电影| 91福利精品视频| 青青免费在线视频| 高清视频欧美一级| 999久久久精品一区二区| 性生活免费观看视频| 精品一区二区三区日韩| 性猛交娇小69hd| 一本色道亚洲精品aⅴ| 亚洲欧美综合一区二区| 久久久久久欧美| 永久免费精品视频| 少妇一晚三次一区二区三区| 国产综合成人久久大片91| 国产精品久久久视频| 色999日韩国产欧美一区二区| 日本黄在线观看| 91av视频在线免费观看| 亚洲美女久久| 欧美韩国日本在线| 久久亚洲一区二区三区明星换脸| 日韩少妇裸体做爰视频| 亚洲精品99999| 日产福利视频在线观看| 激情欧美一区二区三区中文字幕| 好吊日精品视频| 俄罗斯黄色录像| 五月婷婷色综合| 五月婷婷深深爱| 69视频在线免费观看| 欧美理论电影在线精品| 2022亚洲天堂| 国产日韩欧美亚洲| 97国产精品久久久| 欧美成人在线免费| 国产色噜噜噜91在线精品| 国产精品专区在线| 久久综合色播五月| 国产亚洲久一区二区| 最近的2019中文字幕免费一页 | 日韩欧美综合一区| 激情图片在线观看高清国产| 精品久久一区二区三区蜜桃| 欧美亚洲网站| 国产一二三av| 日韩一级片在线播放| 蜜桃视频m3u8在线观看| 茄子视频成人在线观看 | 人人干在线视频| 亚洲精品免费网站| 136国产福利精品导航网址| 国精产品一区一区三区免费视频| 色婷婷亚洲综合| 国产cdts系列另类在线观看| 国产经典一区二区三区 | 永久av免费在线观看| 亚洲电影一区二区| porn亚洲| 97久久天天综合色天天综合色hd| 亚洲欧洲一区二区天堂久久| 四虎永久免费在线观看| 制服丝袜中文字幕一区| a级片在线免费| 视频一区亚洲 | 91.成人天堂一区| 里番在线播放| 亚洲人一区二区| 不卡影院免费观看| 91亚洲视频在线观看| 97在线精品国自产拍中文| 国产精品国内免费一区二区三区| 日韩少妇一区二区| 欧美日韩免费高清一区色橹橹 | 国内久久视频| 欧美激情亚洲色图| 亚洲第一精品夜夜躁人人躁 | 国产伦精品一区二区三区四区免费| 噜噜噜在线观看免费视频日韩 | 免费在线观看你懂的| 日韩一区二区三区精品视频| 波多视频一区| 欧美视频在线第一页| 欧美国产乱子伦| 亚洲欧美日韩成人在线| 91国产在线免费观看| 免费在线成人网|