調用帶引用參數的委托
如果委托有引用參數,參數值會根據調用列表中的一個或多個方法的返回值而改變。
在調用委托列表中的下一個方法時,參數的新值(不是初始值)會傳給下一個方法。例如,
如下代碼調用了具有引用參數的委托。圖14-11演示了這段代碼。
delegate void MyDel(ref int X);class MyClass
{public void Add2(ref int x){x+=2;}public void Add3(ref int x){x+=3;}static void Main(){MyClass mc=new MyClass();MyDel mDel=mc.Add2;mDel+=mc.Add3;mDel+=mc.Add2;int x=5;mDel(ref x);Console.WriteLine($"Value:{x}");}
}
匿名方法
至此,我們已經介紹了使用靜態方法或實例方法來實例化委托。在這種情況下,方法本身都
可以被代碼的其他部分顯式調用,當然,這個部分必須是某個類或結構的成員。
然而,如果方法只會被使用一次一一用來實例化委托會怎么樣呢?在這種情況下,除了創建
委托的語法需要,沒有必要創建獨立的具名方法。匿名方法讓我們無須使用獨立的具名方法。
匿名萬法(anonymousmethod)是在實例化委托時內聯(inline)聲明的方法。例如,圖14-12
演示了同一個類的兩個版本。左邊的版本聲明并使用了一個名為Add20的方法。右邊的版本使用
了匿名方法。沒有底色的代碼部分對于兩個版本是一樣的。
使用匿名方法
我們可以在如下地方使用匿名方法。
- 聲明委托變量時作為初始化表達式。
- 組合委托時在賦值語句的右邊。
- 為委托增加事件時在賦值語句的右邊。第15章會介紹事件。
匿名方法的語法
匿名方法表達式的語法包含如下組成部分。
- delegate類型關鍵字。
- 參數列表,如果語句塊沒有使用任何參數則可以省略。
- 語句塊,它包含了匿名方法的代碼。
返回類型
匿名方法不會顯式聲明返回值。然而,實現代碼本身的行為必須通過返回一個與委托的返回
類型相同的值來匹配委托的返回類型。如果委托有void類型的返回值,匿名方法就不能返回值。
例如,在如下代碼中,委托的返回類型是int。因此匿名方法的實現代碼也必須在代碼路徑
中返回int。
delegate int OtherDel(int Inparam);static void Main()
{OtherDel del=delegate(int x){return x+20; //返回一個整數類型};
}
參數
除了數組參數,匿名方法的參數列表必須在如下3方面與委托匹配:
- 參數數量;
- 參數類型及位置;
- 修飾符。
可以通過使圓括號為空或省略圓括號來簡化匿名方法的參數列表,但必須滿足以下兩個
條件: - 委托的參數列表不包含任何out參數;
- 若名方法不使用任何參數。
例如,如下代碼聲明了一個沒有任何out參數的委托,和一個沒有使用任何參數的匿名方法。
由于兩個條件都滿足了,所以可省略匿名方法的參數列表。
delegate void SomeDel(int X); //聲明委托類型
SomeDel SDel=delegate //省略參數列表
{PrintMessage();CleanUp();
}
params參數
如果委托聲明的參數列表包含了params參數,那么匿名方法的參數列表將忽略params關鍵
字。例如,在如下代碼中:
- 委托類型聲明指定最后一個參數為params類型的參數;
- 然而,匿名方法參數列表必須省略關鍵字。
//在委托類型聲明中使用params關鍵字
delegate void SomeDel(int X,params int[] Y);//在匹配的匿名方法中省略關鍵字
SomeDel mDel =delegate(int X,int [] Y)
{...
};
變量和參數的作用域
參數以及聲明在匿名方法內部的局部變量的作用域限制在實現代碼的主體之內,如圖14-13主
所示。
例如,上面的名方法定義了參數Y和局部變量z。在匿名方法主體結束之后,y和z就不
在作用域內了。最后一行代碼將會產生編譯錯誤。
外部變量
與委托的具名方法不同,匿名方法可以訪問它們外圍作用域的局部變量和環境。
- 外圍作用域的變量叫作外部變量(outervariable)。
- 用在匿名方法實現代碼中的外部變量稱為被方法捕獲。
例如,圖14-14中的代碼演示了定義在匿名方法外部的變量×。然而,方法中的代碼可以訪
問×并輸出它的值。
捕獲變量的生命周期的擴展
只要捕獲方法是委托的一部分,即使變量已經離開了作用域,捕獲的外部變量也會一直有效。
例如,圖14-15中的代碼演示了被捕獲變量的生命周期的擴展。
- 局部變量x在塊中聲明和初始化。
- 然后,委托mDel匿名方法初始化,該匿名方法捕獲了外部變量x。
- 塊關閉時,x超出了作用域。
- 如果取消塊關閉之后的WriteLine語句的注釋,就會產生編譯錯誤,因為它引用的×現在
已經離開了作用域。 - 然而,mDel委托中的匿名方法在它的環境中保留了x,并在調用mDeI時輸出了它的值。