你認識的C# foreach語法糖,真的是全部嗎?

? ? ? ? 本文的知識點其實由golang知名的for循環陷阱發散而來, 對應到我的主力語言C#, 其實牽涉到閉包、foreach。為了便于理解,我重新組織了語言,以倒敘結構行文。

先給大家提煉出一個C#題:觀察for、foreach閉包的差異

c00da90cbfbfe5e3b0086ad9fd85e4e6.png


左邊輸出 5個5;右邊輸出0,1,2,3,4, 答對的、不屑看題的同學都可以出門右轉了。


閉包是在詞法環境中捕獲自由變量的頭等函數, 題中關鍵是捕獲的自由變量。

這里面有3個關鍵名詞,希望大家重視,可以圍觀我之前的 👇新來的總監,把C#閉包講得那叫一個透徹[1]

demo1

  • for循環內閉包,局部變量i是被頭等函數引用的自由變量;相對于每個頭等函數,i是全局變量;

  • 閉包捕獲變量i的時空和 閉包執行的時空不是一個時空;

  • 所有閉包執行時,捕獲的都是變量i,所以執行輸出的都是i++最后的5。

這也是C#閉包的陷阱, 通常應對方式是循環內使用一個局部變量解構每個閉包與(相對全局)變量i的關系。

var?t1?=?new?List<Action>();for?(int?i?=?0;?i?<?5;?i++){//?使用局部變量解綁閉包與全局自由變量i的關系,現在自由變量是局部變量j了。var?j?=?i;var?func?=?(()?=>{Console.WriteLine(j);});t1.Add(func);}foreach?(var?item?in?t1){item();}

demo2

foreach內閉包,為什么能輸出預期的0,1,2,3,4。

聰明的讀者可以猜想,是不是foreach在循環迭代時 ,給我們搞出了局部變量j,幫我們解構了閉包與全局自由變量i多對1的關系。

foreach的底層實現有賴于IEnumerableIEnumerator兩個接口的實現、

這里也有一個永久更新的原創文,👇IEnumerator、IEnumerable還傻傻分不清楚?[2]

但是怎么用這個兩個接口,還需要看foreach偽代碼,??

C# foreach foreach (V v in x) ?embedded_statement?被翻譯成下面代碼:

{E?e?=?((C)(x)).GetEnumerator();try{while?(e.MoveNext()){V?v?=?(V)(T)e.Current;?//?注意,?變量v的定義是在循環體內?embedded_statement?}}finally{...?//?Dispose?e}
}

👇foreach官方信源[3]

請注意注釋,變量v的定義是在while循環內部, 因此使用foreach迭代時,每個閉包捕獲的都是局部的自由變量, 因此foreach閉包執行能輸出0,1,2,3,4。

如果變量V v定義在while語言上方,那么效果就和for循環一樣了。

這是for循環/foreach迭代一個很有意思的差異。


再來看看引發我思考的Golang的for循環陷阱, Golang只有for循環,沒有while,foreach關鍵字。?

package?mainimport?"fmt"var?slice?[]func()
//for循環產生閉包切片
func?main()?{sli?:=?[]int{1,?2,?3,?4,?5}for?_,?v?:=?range?sli?{fmt.Println(&v,?v)slice?=?append(slice,?func()?{fmt.Println(v)?})}for?_,?val?:=?range?slice?{val()}
}
---?output?---
0xc00001c098?1
0xc00001c098?2
0xc00001c098?3
0xc00001c098?4
0xc00001c098?5
5
5
5
5
5

golang for循環作用在切片上,使用姿勢類似于C#的 foreach,但是內核卻是c# for循環。

每個閉包引用的都是(相對全局的)自由變量v,最終閉包拿到的是一個變量的最終值。
應對這種陷阱的思路,依舊是使用循環內局部變量去解構閉包與(相對全局)z自由變量v的關系。

畫外音

本文其實內容很多:

  • 閉包:是在詞法環境中捕獲自由變量的頭等函數

  • foreach 語法糖:依賴于IEnumerable和IEnumerator 接口實現,同時 foreach每次迭代使用的是塊內局部變量, for循環變量是相對的全局變量, 也正是這個差異,導致了投票題的結果。

    每一個知識點都是重要且晦澀,篇幅有限,請適時關注文中給出的幾個永久更新地址,也請各大佬斧正,協助我永久更新????。

參考資料

[1]

👇新來的總監,把C#閉包講得那叫一個透徹: https://www.cnblogs.com/JulianHuang/p/14618378.html

[2]

👇IEnumerator、IEnumerable還傻傻分不清楚?: https://www.cnblogs.com/JulianHuang/p/14271285.html

[3]

👇 foreach官方信源: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/statements#1295-the-foreach-statement

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/281058.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/281058.shtml
英文地址,請注明出處:http://en.pswp.cn/news/281058.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C#對window 硬件類操作,ManagementObjectSearcher

原文轉載&#xff1a;http://blog.csdn.net/da_keng/article/details/50589145 純屬轉載&#xff0c;復制過來方便編程時尋找。感謝作者&#xff1a;I-Awakening復制前補充&#xff1a; 在剛學C#&#xff0c;用ManagementObjectSearcher 竟然不能解析到頭文件&#xff0c;需要手…

2018第51周日

從人們開始用電腦開始就面臨著文件版本控制的問題&#xff0c;從最原始的同一個文檔多個不同命名表示版本到使用本地的文件版本管理&#xff0c;到后面集中式版本管理如2000年的SVN&#xff0c;到再后來的分布式的版本控制系統&#xff0c;如2005年的Git。到現在用的最多的版本…

twitter批量取消關注_如何在Twitter上取消阻止“潛在敏感內容”

twitter批量取消關注Twitter推特Twitter blocks some tweets with a “potentially sensitive content” warning. You can disable this warning—even on an iPhone or iPad, where the option isn’t normally available. You can also disable sensitive content warnings …

mysql數值類型總結及常用函數

最近在學習下&#xff0c;總結一下mysql數值類型&#xff1b; mysql字符類型分&#xff1a; 1、整數類型&#xff1a; 字節 值范圍 INTERGER 1 -127-128 SMALLINT 2 MEDIUMINT…

Semantic-UI的React實現(二):CSS類構造模塊

更簡單的類名標簽 Semantic-UI使用了更簡單的類名聲明。用過Bootstrap的同學都會被其復雜的類名標簽折磨過&#xff0c;例如一個簡單的按鍵樣式&#xff0c;不論顏色或是大小&#xff0c;都需要btn-前綴聲明&#xff1a; <button type"button" class"btn btn…

skype自動回復_如何在Windows 10上阻止Skype自動啟動

skype自動回復Microsoft微軟The Skype app included with Windows 10 now has a notification area icon. That’s great, but what if you never use Skype and don’t want it starting every time you sign in? Here’s how to get rid of it. Windows 10隨附的Skype應用程…

Vue 組件實例屬性的使用

前言 因為最近面試了二、三十個人&#xff0c;發現大部分都還是只是停留在 Vue 文檔的教程。有部分連教程這部分的文檔也沒看全。所以稍微寫一點&#xff0c;讓新上手的 Vuer 多了解 Vue 文檔的其他更需要關注的點。 因為 Vue 文檔已經是個很成熟的文檔&#xff0c;并且實現的 …

C# 讀取硬盤信息類

在編寫工具檢查硬盤信息時&#xff0c;總結常用到的類&#xff1a; Win32_DiskDrive 這個用了檢查整個硬盤的信息&#xff0c;如果電腦只有一個硬盤&#xff0c;那只顯示一條信息。參考如下代碼&#xff0c;AddTextBox為自定義顯示函數。&#xff08;MSDN class 查詢&#xff1…

95后滬漂女孩深陷“狠”且“卷”職場,向上思維,永不過時!

hi&#xff0c;這里是桑小榆。最近和一個伙伴oncall了很久&#xff0c;對我的文章以及思想轉變產生了很大的共鳴&#xff0c;她向我分享了一些職場經歷還有成長經歷等&#xff0c;她的這些經歷也讓我引發了一定的思考。光光&#xff0c;最近剛升任了部門主管&#xff0c;對于當…

PHP:6種GET和POST請求發送方法

在i94web博客中&#xff0c;我試過了暢言和多說兩種社會化評論框&#xff0c;后來還是拋棄了暢言&#xff0c;不安全。 無論是暢言還是多說&#xff0c;我都需要從遠程抓取文章的評論數&#xff0c;然后存入本地數據庫。對于多說&#xff0c;請求的格式如下&#xff1a; // 獲取…

解決Ubuntu 16.04下提示boot分區空間不足的辦法

原文地址: http://www.jb51.net/article/106976.htm   https://www.linuxidc.com/Linux/2015-09/123227.htm 因為linux內核一直在更新&#xff0c;更新后&#xff0c;舊的內核就不在使用&#xff0c;但舊的內核文件還在boot里面&#xff0c;占據著空間&#xff0c;更新幾次過…

3d鏡頭 適配_您是否應該將鏡頭適配器與無反光鏡相機一起使用?

3d鏡頭 適配Canon佳能Mirrorless cameras aren’t the future, they’re the present. If you’re switching from an older DSLR, though, the obvious thing to do is just buy an adapter so you can keep using your old gear. 無反光鏡相機不是未來&#xff0c;而是現在。…

C#彈窗提示并自動關閉方法

剛學C#不久&#xff0c;就寫個工具&#xff0c;總結寫一個簡便自定義提示窗口方法&#xff0c;并自動關閉。 1.在項目添加windows form&#xff08;非user control&#xff09;&#xff0c;命名為Form_wait。 2.在Form_wait,加入需要控件與一個定時器timer1。 數字10為計時顯…

dotNET 7:最小 API 使用

最小 API 并不是在 .NET 7 中才加入的&#xff0c;記得應該是在 .NET 6 中就已經提供&#xff0c;只是對我來說&#xff0c;到現在才開始使用。創建一個最小 API在 VS 2022 中創建 WebAPI 項目&#xff0c;不勾選使用控制器&#xff0c;創建出來的就是最小 API &#xff1a;不勾…

Taro小程序采坑記

Taro&#xff0c;京東凹凸實驗室出品的適配多端的一個框架&#xff0c; Taro 是一套遵循 React 語法規范的 多端開發 解決方案。現如今市面上端的形態多種多樣&#xff0c;Web、React-Native、微信小程序等各種端大行其道&#xff0c;當業務要求同時在不同的端都要求有所表現的…

struts入門

struts工作過程&#xff1a; 反射代碼&#xff1a; Class clazz Class.forName("action全路徑"); Method m clazz.getMethod("execute"); Object o m.invoke(); package標簽&#xff1a; 轉發&#xff1a;地址欄不變 修改struts默認常量值&#xff1a; 常…

《Android應用開發攻略》——2.14 備份Android應用程序數據

2.14 備份Android應用程序數據 Pratik Rupwal2.14.1 問題當用戶恢復出廠設置或者改用新的Android設備時&#xff0c;應用程序丟失存儲數據或者應用程序設置。2.14.2 解決方案Android的Backup Manager&#xff08;備份管理器&#xff09;能夠在應用程序重新安裝時自動恢復備份數…

C#程序開機啟動與獲取程序啟動路徑

寫windows工具時&#xff0c;要進行電源管理&#xff0c;需要重啟與開關機OS&#xff0c;這樣工具就需要自動啟動。查了網上很多資料&#xff0c;修改注冊列表就可以。 但是&#xff0c;復制幾個網站的代碼并自己修改都發現不行&#xff0c;最后發現腳本之家這段代碼才成功&am…

wpf office 菜單_如何帶回Office 2007中的舊菜單

wpf office 菜單Using the new Ribbon feature in Office 2007 takes time to learn…time you don’t have because projects are stacking up. Today we will look at UBitMenu, a utility that puts the familiar Office 2003 menu into the 2007 ribbon. 使用Office 2007中…

Swagger UI 僅為用戶暴露已授權終結點

前言當需要在生產環境中提供 Swagger UI 時&#xff0c;我們可以通過身份驗證&#xff0c;控制只有授權用戶才能訪問 Swagger UI 頁面。但是我們希望更進一步&#xff0c;每個用戶只能看到授權給他的終結點&#xff0c;而不會暴露其他未授權終結點信息。比如&#xff0c; API 提…