C# 提供 delegate 修飾子來宣告一個委派方法:
public delegate String getNameDelegate(String n);
委派方法的參數個數、順序、型態乃至於回傳型態都必須跟要被委派的方法一樣 (但變數名稱可以不相同)。下面是我們要委派這個 getNameDelegate 方法呼叫的一個方法:
public static String getName(String name){
return "g1: " + name;
}
所以我們把 getName 想成打開電視機,getNameDelegate 當作遙控器,這樣可以多少理解吧?
要呼叫委派方法,有許多方法,隨著 C# 版本的演進已經越來越方便,就從最複雜的開始說起吧。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1 {
class Program {
public delegate String getNameDelegate(String n);
static void Main(string[] args) {
getNameDelegate g0 = new getNameDelegate(getName);
getNameDelegate g1 = getName;
getNameDelegate g2 = delegate(String n) { return "g2: " + n; };
getNameDelegate g3 = n => "g3: " + n;
Console.WriteLine(g0("0"));
Console.WriteLine(g1("1"));
Console.WriteLine(g2("2"));
Console.WriteLine(g3("3"));
Console.ReadKey();
}
public static String getName(String name){
return "g1: " + name;
}
}
}
首先是 getNameDelegate g0 = new getNameDelegate(getName); 這段,這是最早的方法。你就將 getNameDelegate 給實體化,並在其建構元上指定要代為執行的方法 (如 getName) 就可以了。
因為這樣太麻煩,所以後來的 C# 支援這種寫法:getNameDelegate g1 = getName; 是不是更直覺呢?
C# 2.0 中,增加了匿名方法的建立,像我們的 getName 這麼簡單的一行,可以簡化為
getNameDelegate g2 = delegate(String n) { return "g2: " + n; };
這樣,利用 delegate(){ } 來定義匿名方法。
C# 3.0 中,更以 Lambda 運算式取代匿名方法,一行 getNameDelegate g3 = n => "g3: " + n; 輕鬆打發。 n => "g3: " + n; 就是所謂的 Lambda 運算式。例如 x => x * x 就是「傳入 x,執行 x * x 並回傳」。
最後準備好 g1 等委派物件後,就可以開始執行了。執行的方式有兩種,一種是 g1.Invoke(); 來引發,另一種是更為直覺的 g1(); 直接執行。
這麼看起來委派只是代為執行,並沒有什麼好用的感覺啊。像上面的例子,我大可直接呼叫 getName() 就好,為什麼還要繞一圈以 getNameDelegate 包裝起來再呼叫呢?脫褲子放屁嗎?
getNameDelegate g1 = getName;
g1("Scribe");
getName("Scribe");
They're the same!
雖然我現在還搞不懂委派有什麼好的,不過我發現委派他可以一次呼叫代為多個方法,這樣就比較有用多了。例如我按下遙控器的開關,就可以幫我把電視、冷氣、電燈等開關一次打開,不是很方便嗎?所以下面要教你怎麼一次委派多個方法。
using System;
namespace ConsoleApplication1 {
class Program {
public delegate void consoleDelegate(String txt);
public delegate void printNameDelegate(String n, consoleDelegate p);
static void Main(string[] args) {
var g0 = new printNameDelegate(printName);
g0 += delegate(String n, consoleDelegate p) { p("Call from anonymous func: " + n); };
g0 += (n, p) => p("Call from Lambda: " + n);
g0("scribe", print2Console);
Console.ReadKey();
}
public static void printName(String name, consoleDelegate p) {
p(name);
}
public static void print2Console(String txt){
Console.WriteLine(txt);
}
}
}
Result:
scribe
Call from anonymous func: scribe
Call from Lambda: scribe
var g0 = new printNameDelegate(printName);
g0 += delegate(String n, consoleDelegate p) { p("Call from anonymous func: " + n); };
g0 += (n, p) => p("Call from Lambda: " + n);
上面三行分別以不同的方式創造出委派物件,跟上面範例的不同點是以 += 串接,讓 g0 一次代理多個方法,最後再一次執行。所以 g0() 的結果有三行。這樣就可以呼叫一個委派物件,同時作數件事情了。
值得一提的是本範例用了兩個 delegate,其中一個用在 print2Console 上,讓其他方法能夠叫用。printName 第二個參數就是 delegate,其實很像是方法的指標之類的。(因為不可以直接指定第二個變數型別為 print2Console,所以使用委派方式)
我比較喜歡 delegate{} 建立匿名方法跟直接使用 () 來呼叫委派物件,你呢?
參考資料:C# 筆記:重訪委派-從 C# 1.0 到 2.0 到 3.0
沒有留言:
張貼留言