天天看點

匿名方法

匿名方法定義

匿名方法的聲明

匿名方法的使用

範圍捕獲局部變量或執行個體狀态

匿名函數會捕獲變量,并延長對象的生命周期

結束匿名方法捕獲局部變量-靜态匿名函數

匿名方法是沒有名稱隻有主體的方法。 在匿名方法中您不需要指定傳回類型,它是從方法主體内的 return 語句推斷的。 匿名方法是通過使用 delegate 關鍵字建立委托執行個體來聲明的。

第一種方式:<code></code>

第二種方式:可以将建立的匿名方法轉換為具有任何參數清單的委托類型。這是 lambda 表達式不支援的匿名方法的唯一功能。 在所有其他情況下,lambda 表達式是編寫内聯代碼的首選方法。

從 C# 9.0 開始,可以使用棄元指定該方法不使用的兩個或更多個匿名方法輸入參數:

<code></code>為實作向後相容性,如果隻有一個參數名為 <code>_</code>,則将 <code>_</code> 視為匿名方法中該參數的名稱。

從 C# 9.0 開始,可以在匿名方法的聲明中使用 <code>static</code> 修飾符:

靜态匿名方法無法從封閉範圍捕獲局部變量或執行個體狀态。

 總結:

匿名函數會捕獲目前上下文的局部變量,捕獲是引用位址不是指派,延長對象的生命周期; 捕獲的變量将不會被作為垃圾回收,直到此委托或表達式樹被回收掉。

這邊說的目前上下文就是private public interal protected聲明的那些指函數、變量等多作用域範圍

也就是說,隻要某個方法中存在沒有被回收的匿名函數/lambda 表達式/表達式樹,那麼目前上下文的對象直到這些匿名函數被回收之前都不會被回收,即便已經設為了 null。

案例:

測試代碼是這樣的:

需要驗證的是 <code>MainPage</code> 對象是否被回收。然而在這段代碼中,<code>MainPage</code> 并沒有被回收;然而去掉最後一行,<code>MainPage</code> 便可以正常回收。關鍵是,即便是在 Console.WriteLine 上打下斷點,讓代碼永遠不會執行到最後一句,也不會改變回收的結果。

由于 <code>DoSomething</code> 中的委托參數恰好就是 <code>MainPage</code> 類型的,不禁讓人覺得可能是此函數做了一些奇怪的事情。然而畢竟參數中傳入的委托參數隻是形參,理論上不應該影響到外部對象的回收。那麼影響的隻可能是變量的捕獲了。

于是,我們将最後一行換成别的函數别的參數:

或者将整個這一句提取成新的函數:

那麼,回收就會正常進行。

現在,不執行這個受争議的函數了,我們使用空的匿名函數。

一樣會導緻不回收。

在微軟官方的《C# 規範 5.0》(點此下載下傳)的第 7.15.5.1 章節中有說到:

When an outer variable is referenced by an anonymous function, the outer variable is said to have been captured by the anonymous function. Ordinarily, the lifetime of a local variable is limited to execution of the block or statement with which it is associated (§5.1.7). However, the lifetime of a captured outer variable is extended at least until the delegate or expression tree created from the anonymous function becomes eligible for garbage collection.
匿名方法

匿名函數會捕獲目前上下文的局部變量,延長對象的生命周期;直到此委托或表達式樹被回收掉。

您可以在lambda或匿名方法上利用static修飾符,以確定您不會無意中從封閉的上下文中捕獲本地或執行個體狀态。這對于提高應用程式的性能非常友好。

程式設計是個人愛好