2009-04-17 57 views
12

我一直在reading this article about closures他們說:關閉有什麼特別之處?

  • 「所有的管道是自動的」
  • 編譯「將創建一個包裝類」和「擴展了變量的生命」
  • 「你可以使用局部變量不用擔心」
  • 的.NET編譯器採用管道對你的關心,等

所以我做了根據他們的代碼,並給我一個例子,它似乎儘管閉包的行爲與普通的命名方法類似,它們也「無需擔心局部變量」,並且「所有管道都是自動的」。

或者這個「局部變量的包裝」解決了什麼問題使得閉包變得如此特別/有趣/有用?

using System; 
namespace TestingLambda2872 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Func<int, int> AddToIt = AddToItClosure(); 

      Console.WriteLine("the result is {0}", AddToIt(3)); //returns 30 
      Console.ReadLine(); 
     } 

     public static Func<int, int> AddToItClosure() 
     { 
      int a = 27; 
      Func<int, int> func = s => s + a; 
      return func; 
     } 
    } 
} 

回答

所以,這個問題的答案之一就是閱讀Jon Skeet's article on closures是馬克指出。本文不僅展示了C#中lambda表達式的演變過程,還展示瞭如何在Java中處理閉包,這是本主題的絕佳讀物。

+0

其他語言(如Javascript)支持關閉。你在問關於這個概念還是C#的具體實現? – strager 2009-04-17 10:09:21

+1

我認爲這個例子太簡單,無法理解封閉的力量。 – 2009-04-17 10:12:00

回答

20

你的例子不清楚,並沒有(IMO)顯示典型的捕獲用法(唯一捕獲的是a,它總是3,所以不是很有趣)。

考慮這種教科書的例子(謂語):

List<Person> people = ... 
string nameToFind = ... 
Person found = people.Find(person => person.Name == nameToFind); 

現在嘗試它沒有關閉;你需要做更多的工作,即使我們是懶惰:

PersonFinder finder = new PersonFinder(); 
finder.nameToFind = ... 
Person found = people.Find(finder.IsMatch); 
... 
class PersonFinder { 
    public string nameToFind; // a public field to mirror the C# capture 
    public bool IsMatch(Person person) { 
     return person.Name == nameToFind; 
    } 
} 

捕獲方法在不同的範圍還擴展到大量的變量 - 複雜的很多是隱藏的。

除了名稱之外,上面是C#編譯器在後臺執行的操作的近似值。請注意,當涉及其他範圍時,我們將開始鏈接不同的捕獲類(即內部範圍對外部範圍的捕獲類的引用)。相當複雜。

Jon Skeet有很好的article on this here,以及更多in his book

0

閉包是編譯器的一個功能。你沒有看到它,它只是讓你編寫的代碼工作。

沒有它,對AddToIt(3)的調用將失敗,因爲底層lamda在AddToItClusure()的作用域中使用局部變量a = 27。 AddToIt被調用時,該變量不存在。

但由於Closure是編譯器使用的一種機制,因此代碼有效,您不必關心它。

相關問題