共用方式為


委派和 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);
        }
    }
}

如您所見,委派的主體只是一組表達式,就像任何其他委派一樣。 不過,我們是在呼叫 方法時臨時引入它,而不是將它作為一個單獨的定義。

不過,即使使用此方法,我們仍有許多程式代碼可以丟棄。 這是 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";
    };
}

在此上下文中,+= 運算子用於訂閱事件。 如需詳細資訊,請參閱 如何訂閱和取消訂閱事件

進一步閱讀和資源