來看使用Action委託的一個例項:
static void Main(string[] args){int i = 0;
Action a = () => i++;a();a();Console.WriteLine(i);}
結果是期望能的2。但令人好奇的是:棧上的變數i是如何傳遞給Action委託的?
反編譯進行檢視,首先看Main方法對應的IL程式碼:
再看c_DisplayClass1的IL程式碼:
從中可以看出:
→在託管堆上建立了一個名為c_DisplayClass1的例項
→把棧上變數i的值賦值給了c_DisplayClass1的例項欄位i
→編譯器() => i++;Lambda表示式表示的匿名委託起了個<Main>b_0的方法名,併成為了c_DisplayClass1的例項方法
→把c_DisplayClass1的例項方法<Main>b_0賦值給Action委託變數
→最後呼叫委託2次,這2次都是針對c_DisplayClass1的例項欄位i
換句話說,在託管堆上建立了物件例項,形成"閉包"。棧上的變數變成了閉包的例項欄位,Lambda表示式所表示的匿名委託變成了閉包的例項方法。
以上,建立了一個Action,形成了一個"閉包",接下來建立2個Action,形成2個"閉包",看"閉包"的例項欄位是否相互影響?
static void Main(string[] args){Action a = GetAction();Action b = GetAction();Console.Write("第一次呼叫a,i的值=");
a();Console.WriteLine();Console.Write("第二次呼叫a,i的值=");
a();Console.WriteLine();Console.Write("第一次呼叫b,i的值=");
b();Console.WriteLine();}static Action GetAction()
{Action result = null;
int i = 0;
result = () => Console.Write(i++);return result;
}
以上,雖然是把同一個GetAction方法分別賦值給了Action委託,但GetAction方法分別在不同的"閉包"內,當呼叫委託執行GetAction方法的時候,各自對閉包內的例項欄位i自增1並列印,相互間不影響。
總結:每個Action都有自己的"閉包",並且"閉包"間互不影響。
“委託、Lambda表示式、事件系列”包括: