我為了更好的理解C#中的委託,、泛型委派、匿名方法和Lambda運算式,我把它們的演變過程通過自己的理寫了出來,各位高手要是看到有什麼不妥的地方,還望指出。
首先,我從一個C語言中很簡單的一個問題開始,比較兩個數的大小,並將最大的數以string 型輸出
首先來看比較常規的寫法:
public delegate string DelegateCompare(int Num1,int Num2); //定義委託
class Compare
{
public static string NumCompare(int Num1, int Num2)
{
return Num1 > Num2 ? Num1.ToString() : Num2.ToString();
}
}
class CompareApplication
{
static void Main()
{
DelegateCompare delegate1 = new DelegateCompare(Compare.NumCompare);
string STR = "最大的數位:" + delegate1(10, 20);
Console.WriteLine(STR);
Console.ReadLine();
}
}
為了精簡代碼(當然這個理由似乎不夠充分),我們決定使用匿名方法,也許這裡你並不能看到匿名方法的真正好處,但是,當把.NET方法做為委託參數時或處理時間時,就能看到匿名方法的真正用處。下面是貼過來的代碼:
public delegate string DelegateCompare(int Num1,int Num2); //定義委託
class CompareApplication
{
static void Main()
{
DelegateCompare delegate1 = new DelegateCompare(delegate(int Num1, int Num2) {
return Num1 > Num2 ? Num1.ToString() : Num2.ToString();
});
string STR = "最大的數位:" + delegate1(10, 20);
Console.WriteLine(STR);
Console.ReadLine();
}
}
正如你所見到的一樣,我把Compare類完全刪除了,那比較大小的功能是通過什麼完成的了,這就是匿名方法,通過delegate關鍵字,我們聲明了一個沒有方法名的方法體。
接下來我有個大膽的想法,將委託聲明也去掉,這時就應該用到泛型委派
class CompareApplication
{
static void Main()
{
Func<int, int, string> delegate1 = new Func<int, int, string>(delegate(int Num1, int Num2)
{
return Num1 > Num2 ? Num1.ToString() : Num2.ToString();
});
string STR = "最大的數位:" + delegate1(10, 20);
Console.WriteLine(STR);
Console.ReadLine();
}
}
在上面的代碼中,我將委託的聲明全部用Func<int, int, string>替代掉了,我先分析一下該運算式如何得來,先看我們的委託是如何定義的:
public delegate string DelegateCompare(int Num1,int Num2),從委託的聲明中我們得知,綁定到該委託的方法必須具有兩個int型參數並且其傳回值類型為string,那麼泛型委派Func<int, int, string>的得來就一目瞭然了。
這時,所有的代碼都集中在一個函數裡了,夠精簡了,還能不能更加精簡了,好,這時候lambda運算式出場了
class CompareApplication
{
static void Main()
{
Func<int, int, string> delegate1 = (x, y) => x > y ? x.ToString() : y.ToString();
string STR = "最大的數位:" + delegate1(10, 20);
Console.WriteLine(STR);
Console.ReadLine();
}
}
我們一定能看出來,這裡面最重要的就是這句:Func<int, int, string> delegate1 = (x, y) => x > y ? x.ToString() : y.ToString()。我想我有必要把這句話完整的解釋一遍,首先我想知道這句話幹了點啥事,它做的事還真不少,定義委託、方法綁定、方法定義,這三件事一氣呵成。首先來看委託的定義:Func<int, int, string> delegate1,這段代碼告訴我們,我們定義了一個可以綁定具有兩個int型參數並且其傳回型別為string型的方法的委託,接下來看等號右邊,這裡就是一個lambda運算式,lambda運算式可以看作是一個匿名方法,以“=>”運算子為標誌,“=>”左邊部分為傳入該匿名方法的兩個參數,注意,這兩個參數我們沒有宣告類型,但編譯器會根據前面泛型委派的定義自動推斷出其參數類型(傳回值類型是同樣的原理)。“=>”右邊為傳回值。
好了,上面就是我對這些概念的理解。本人是個初學者,還請各位高手多多指教。
補充幾點:(摘自MSDN)
只有在 Lambda 有一個輸入參數時,括弧才是可選的;否則括弧是必需的。 兩個或更多輸入參數由括在括弧中的逗號分隔
有時,編譯器難於或無法推斷輸入類型。 如果出現這種情況,您可以按以下樣本中所示方式顯式指定類型:(int x, string s) => s.Length > x
使用空括弧指定零個輸入參數:() => SomeMethod()
Lambda 語句與 Lambda 運算式類似,只是語句括在大括弧中:
(input parameters) => {statement;}
Lambda 語句的主體可以包含任意數量的語句;但是,實際上通常不會多於兩個或三個語句。
delegate void TestDelegate(string s);…TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };myDel("Hello");
在編寫 Lambda 時,通常不必為輸入參數指定類型,因為編譯器可以根據 Lambda 主體、基礎委託類型以及 C# 語言規範中描述的其他因素推斷類型。
Lambda 的一般規則如下:
Lambda 包含的參數數量必須與委託類型包含的參數數量相同。
Lambda 中的每個輸入參數必須都能夠隱式轉換為其對應的委託參數。
Lambda 的傳回值(如果有)必須能夠隱式轉換為委託的傳回型別。
請注意,Lambda 運算式本身沒有類型,因為常規類型系統沒有“Lambda 運算式”這一內部概念。但是,有時會不正式地論及 Lambda 運算式的“類型”。 在這些情況下,類型是指委託類型或 Lambda 運算式所轉換為的 Expression 類型。