委派會定義類型,表示具有特定參數清單和傳回型別之方法的參考。 方法(靜態或實例),其參數清單和回傳型別若符合某個類型,就可以被指派給該類型的變數,然後可以直接使用(並使用適當的引數)呼叫,或作為引數本身傳遞至另一個方法並進行呼叫。 下列範例示範委派的用法。
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<>,而且不需要定義新的委派類型即可使用。 三種類型之間有一些差異,這些差異與它們預期的使用方式有關:
-
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);
}
}
}
如您所見,委派的主體只是一組表達式,就像任何其他委派一樣。 不過,我們是在呼叫 方法時臨時引入它,而不是將它作為一個單獨的定義。
不過,即使使用此方法,我們仍有許多程式代碼可以丟棄。 這是 Lambda 運算式 發揮作用的地方。 在 C# 3.0 中,引入的 Lambda 表達式,或簡稱為「Lambda」,是語言整合查詢 (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";
};
}
在此上下文中,+= 運算子用於訂閱事件。 如需詳細資訊,請參閱 如何訂閱和取消訂閱事件。