基礎知識---委託和 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<>,可用於 .NET API 的各個位置,無需定義新委託類型。 固然,從這三者的簽名能夠看出它們之間存在某些差別,主要影響其既定用途:api

  • Action<> 用於須要使用委託參數執行操做的狀況。
  • Func<> 一般用於現有轉換的狀況,也就是說須要將委託參數轉換爲其餘結果時。 最好的示例就是投影。
  • Predicate<> 用於須要肯定參數是否知足委託條件的狀況。 也可將其寫做 Func<T, bool>

如今可以使用 Func<> 委託而非自定義類型從新編寫上述示例。 程序將照舊繼續運行。this

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 引入了匿名委託的概念。 在其支持下,可建立「內聯」委託,而無需指定任何其餘類型或方法。 只需在所需位置內聯委託的定義便可。spa

例如,要進行切換並使用匿名委託篩選出只有偶數的列表,而後將其打印到控制檯。code

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 方法時臨時引入。blog

可是,即便使用此方法,仍有許多能夠丟棄的代碼。 此時就須要使用 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。 再次強調,它只是使用委託的一種很是方便的語法,所以其實際行爲與使用匿名委託時相同。get

再次強調,lambda 只是委託,這意味着可將其順利用做事件處理程序,如如下代碼片斷所示。

public MainWindow()
{
    InitializeComponent();

    Loaded += (o, e) =>
    {
        this.Title = "Loaded";
    };
}

此上下文中的 += 運算符用於訂閱事件。

相關文章
相關標籤/搜索