委托定義類型,類型指定特定方法簽名。 可將滿足此簽名的方法(靜態或實例)分配給該類型的變數,然後(使用適當參數)直接調用該方法,或將其作為參數本身傳遞給另一方法再進行調用。 以下示例演示了委托的用法。 public delegate string Reverse(string s); 行創建特定簽名 ...
委托定義類型,類型指定特定方法簽名。 可將滿足此簽名的方法(靜態或實例)分配給該類型的變數,然後(使用適當參數)直接調用該方法,或將其作為參數本身傳遞給另一方法再進行調用。 以下示例演示了委托的用法。
using System; using System.Linq; public class Program { public delegate string Reverse(string s); static string ReverseString(string s) { return new string(s.Reverse().ToArray()); } static void Main(string[] args) { Reverse rev = ReverseString; Console.WriteLine(rev("a string")); } }
public delegate string Reverse(string s);
行創建特定簽名的委托類型,在本例中即接受字元串參數並返回字元串參數的方法。static string ReverseString(string s)
方法與定義的委托類型具有完全相同的簽名,用於實現委托。Reverse rev = ReverseString;
行顯示可將方法分配給相應委托類型的變數。Console.WriteLine(rev("a string"));
行演示如何使用委托類型的變數來調用委托。
為簡化開發過程,.NET 包含一組委托類型,程式員可重用這些類型而無需創建新類型。 其中包括 Func<>
、Action<>
和 Predicate<>
,可用於 .NET API 的各個位置,無需定義新委托類型。 當然,從這三者的簽名可以看出它們之間存在某些差異,主要影響其既定用途:
Action<>
用於需要使用委托參數執行操作的情況。Func<>
通常用於現有轉換的情況,也就是說需要將委托參數轉換為其他結果時。 最好的示例就是投影。Predicate<>
用於需要確定參數是否滿足委托條件的情況。 也可將其寫作Func<T, bool>
。
現在可使用 Func<>
委托而非自定義類型重新編寫上述示例。 程式將照舊繼續運行。
using System; using System.Linq; public class Program { static string ReverseString(string s) { return new string(s.Reverse().ToArray()); } static void Main(string[] args) { Func<string, string> rev = ReverseString; Console.WriteLine(rev("a string")); } }
對於此簡單示例而言,在 Main
方法之外定義方法似乎有些多餘。 因此 .NET Framework 2.0 引入了匿名委托的概念。 在其支持下,可創建“內聯”委托,而無需指定任何其他類型或方法。 只需在所需位置內聯委托的定義即可。
例如,要進行切換並使用匿名委托篩選出只有偶數的列表,然後將其列印到控制台。
using System; using System.Collections.Generic; public class Program { public static void Main(string[] args) { List<int> list = new List<int>(); for (int i = 1; i <= 100; i++) { list.Add(i); } List<int> result = list.FindAll( delegate (int no) { return (no % 2 == 0); } ); foreach (var item in result) { Console.WriteLine(item); } } }
如你所見,該委托的正文只是一組表達式,其他所有委托也是如此。 但它並非單獨定義,而是在調用List<T>.FindAll 方法時臨時引入。
但是,即使使用此方法,仍有許多可以丟棄的代碼。 此時就需要使用 lambda 表達式。
lambda 表達式(或簡稱“lambda”)在 C# 3.0 中作為語言集成查詢的 (LINQ) 核心構建基塊被首次引入。 這種表達式只是使用委托的更方便的語法。 它們將聲明簽名和方法正文,但在分配到委托之前沒有自己的正式標識。 與委托不同,可將其作為事件註冊的左側內容或在各種 LINQ 子句和方法中直接分配。
由於 lambda 表達式只是指定委托的另一種方式,因此應可重新編寫上述示例,令其使用 lambda 表達式而不是匿名委托。
using System; using System.Collections.Generic; public class Program { public static void Main(string[] args) { List<int> list = new List<int>(); for (int i = 1; i <= 100; i++) { list.Add(i); } List<int> result = list.FindAll(i => i % 2 == 0); foreach (var item in result) { Console.WriteLine(item); } } }
在前面的示例中,所使用的 Lambda 表達式為 i => i % 2 == 0
。 再次強調,它只是使用委托的一種非常方便的語法,因此其實際行為與使用匿名委托時相同。
再次強調,lambda 只是委托,這意味著可將其順利用作事件處理程式,如以下代碼片段所示。
public MainWindow() { InitializeComponent(); Loaded += (o, e) => { this.Title = "Loaded"; }; }
此上下文中的 +=
運算符用於訂閱事件。