委派和 Lambda
委派會定義類型,代表具有特定參數清單及傳回型別的方法參考。 參數清單與傳回型別符合的方法 (靜態或執行個體) 可指派給該類型的變數,然後直接呼叫 (使用適當的引數),或當做引數本身傳遞至另一個方法,再進行呼叫。 下列範例示範委派的用法。
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);
}
}
}
如您所見,委派的主體只是一組運算式,與任何其他委派相同。 但這並不是不同的定義,而是當作「臨機操作」引入 List<T>.FindAll 方法呼叫。
不過,即使使用此方法,還是有許多程式碼可以捨棄。 此時就需要 Lambda 運算式。 Lambda 運算式 (簡稱 "Lambda") 是在 C# 3.0 中,當作 Language Integrated Query (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";
};
}
在此內容中使用 +=
運算子來訂閱事件。 如需詳細資訊,請參閱如何訂閱及取消訂閱事件。