l 如果匿名方法包含簽名,那麼在簽名中指定的參數在塊內是有效的。如果匿名方法不具有簽名,它可以被轉換為具有參數的委托類型(§21.3),但參數在塊內不可訪問。
l 除了在最接近的封閉匿名方法簽名中指定的ref和out參數(如果有的話)以外,對於塊來說訪問ref或者out參數將導致編譯時錯誤。
l 當this的類型是一個結構類型時,對於塊來說,訪問this將導致編譯時錯誤。無論該訪問是顯式的(像this.x)或者隱式的(像對於在結構實例的成員中的x),情況都是如此。該規則只是禁止此類訪問方式,但並不影響在結構中成員查找的結果。
l 塊可以訪問匿名方法的外部變量(§21.5)。當匿名方法表達式被計算(§21.6)的時候,對於外部變量的訪問,將會引用激活的(active)變量的實例。
l 對於塊來說,包含一個其目標在塊之外,或一個內嵌的匿名方法的塊之內的goto語句、break語句或continue語句,將導致編譯時錯誤。
l 在塊內的return 語句,將從最接近的封閉匿名方法調用中返回控制權,而不是從封閉函數成員中返回。在return 語句中指定的表達式必須與某個委托類型兼容,而最接近的匿名方法表達式將被轉換到該委托類型(§21.3)。
執行一個匿名方法的程序塊,除了通過匿名方法表達式的計算和調用(evaluation and invocation)之外,是否還有其他方法,並沒有明確地詳細說明。特別的是,編譯器可以通過合成一個或多個命名方法或類型來實現匿名方法,任何此類合成的元素的名字,必須為編譯器的使用而保留在一個地方:名字必須保留兩個連續下劃字符。
class Test { static D[] F() { D[] result = new D[3]; for (int i = 0; i < 3; i++) { int x = i * 2 + 1; result[i] = delegate { Console.WriteLine(x); }; } return result; }
static void Main() { foreach (D d in F()) d(); } }
產生如下輸出。
1 3 5
但如果將x的聲明移到循環之外
static D[] F() { D[] result = new D[3]; int x; for (int i = 0; i < 3; i++) { x = i * 2 + 1; result[i] = delegate { Console.WriteLine(x); }; } return result; }
static D[] F() { D[] result = new D[3]; int x = 0; for (int i = 0; i < 3; i++) { int y = 0; result[i] = delegate { Console.WriteLine("{0} {1}", ++x, ++y); }; } return result; }
這三個委托捕獲了X的同一實例,但捕獲了Y的多個單獨實例,所以輸出如下。
1 1 2 1 3 1
單獨的匿名方法可以捕獲外部變量的相同實例。例如
using System;
delegate void Setter(int value);
delegate int Getter();
class Test { static void Main() { int x = 0; Setter s = delegate(int value) { x = value; }; Getter g = delegate { return x; }; s(5); Console.WriteLine(g()); s(10); Console.WriteLine(g()); } }
兩個匿名方法捕獲了局部變量X的同一實例,並且它們可以通過該變量“通信”。該示例輸出如下。
5 10
21.6匿名方法計算 匿名方法表達試的運行時計算產生一個引用匿名方法的委托實例,並且被捕獲的外部變量的集合(可能為空)在計算時(the time of the evaluation)是活躍的(active)。當由匿名方法表達式所產生的委托被調用時,匿名方法體就會執行。方法體內的代碼將使用由該委托引用而被捕獲的外部變量執行。
class Test { static double[] Apply(double[] a, Function f) { double[] result = new double[a.Length]; for (int i = 0; i < a.Length; i++) result[i] = f(a[i]); return result; }
static void F(double[] a, double[] b) { a = Apply(a, delegate(double x) { return Math.Sin(x); }); b = Apply(b, delegate(double y) { return Math.Sin(y); }); ... } }