我已經快速閱讀了Microsoft Lambda Expression文檔。C#Lambda表達式:爲什麼我應該使用它們?
這種例子幫助我更好地理解,雖然:
delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
不過,我不明白爲什麼它是這樣一個創新。這只是一個方法,當「方法變量」結束時就會死掉,對嗎?爲什麼我應該使用這個而不是真正的方法?
我已經快速閱讀了Microsoft Lambda Expression文檔。C#Lambda表達式:爲什麼我應該使用它們?
這種例子幫助我更好地理解,雖然:
delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
不過,我不明白爲什麼它是這樣一個創新。這只是一個方法,當「方法變量」結束時就會死掉,對嗎?爲什麼我應該使用這個而不是真正的方法?
Lambda expressions是匿名代理的簡單語法,可以在任何地方使用匿名代理。然而,事實恰恰相反, lambda表達式可以轉換爲表達式樹,從而允許LINQ to SQL等許多魔術。
下面是使用匿名委託然後lambda表達式,以顯示他們是如何對眼睛更容易是一個LINQ to Objects表達的例子:
// anonymous delegate
var evens = Enumerable
.Range(1, 100)
.Where(delegate(int x) { return (x % 2) == 0; })
.ToList();
// lambda expression
var evens = Enumerable
.Range(1, 100)
.Where(x => (x % 2) == 0)
.ToList();
Lambda表達式和匿名委託有優勢寫一個單獨的函數:他們實現了closures,它可以讓你pass local state to the function without adding parameters的功能或創建一次性使用的對象。
Expression trees是C#3.0的一個非常強大的新功能,它允許API查看錶達式的結構,而不是僅僅獲取對可執行方法的引用。一個API只是必須作出委託參數爲Expression<T>
參數,編譯器會生成一個lambda,而不是匿名委託的表達式樹:
void Example(Predicate<int> aDelegate);
叫這樣的:
Example(x => x > 5);
變爲:
void Example(Expression<Predicate<int>> expressionTree);
後者將通過描述表達x > 5
的abstract syntax tree的表示。 LINQ to SQL依靠此行爲可以將C#表達式轉換爲服務器端的過濾/排序等所需的SQL表達式。
很多時候,你只是在一個地方使用功能,所以使一個方法只是使課堂更加混亂。
它節省了必須在特定位置只使用一次的方法,而不是將它們定義在遠離使用位置的地方。好的用途是比較排序等通用算法的比較器,然後可以在調用排序時定義自定義排序函數,而不是遠離強迫您查看其他位置以查看排序內容。
而這不是一項真正的創新。 LISP具有約30年或更長時間的lambda功能。
匿名函數和表達式對於不能從創建完整方法所需的額外工作中受益的一次性方法很有用。
考慮這個例子:
string person = people.Find(person => person.Contains("Joe"));
與
public string FindPerson(string nameContains, List<string> persons)
{
foreach (string person in persons)
if (person.Contains(nameContains))
return person;
return null;
}
這些是功能上等同的。
這是一種採取小型操作並將其放置在非常接近其使用位置的方式(與聲明接近其使用點的變量不同)。這應該讓你的代碼更具可讀性。通過對錶達式進行匿名處理,如果某個人在其他地方使用了該功能並將其修改爲「增強」該功能,那麼對於某人破壞客戶端代碼而言,也會使其變得更加困難。
同樣,爲什麼你需要使用foreach?您可以使用plain for循環執行foreach中的所有操作,也可以直接使用IEnumerable。答:你不需要需要但它使你的代碼更具可讀性。
Lambda表達式是表示匿名方法的簡潔方法。匿名方法和Lambda表達式都允許您以內聯方式定義方法實現,但是,匿名方法明確要求您爲方法定義參數類型和返回類型。 Lambda表達式使用C#3.0的類型推斷功能,它允許編譯器根據上下文來推斷變量的類型。這是非常方便的,因爲這節省了我們很多打字!
這只是使用lambda表達式的一種方式。你可以在任何地方使用一個lambda表達式你可以使用委託。這允許你做這樣的事情:
List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");
strings.Find(s => s == "hello");
此代碼將在列表中找到單詞「你好」相匹配的條目。另一種方式做,這是真正的委託傳遞給查找方法,像這樣:
List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");
private static bool FindHello(String s)
{
return s == "hello";
}
strings.Find(FindHello);
編輯:
在C#2.0,這可以使用匿名委託語法完成:
strings.Find(delegate(String s) { return s == "hello"; });
Lambda明顯清除了該語法。
拉姆達的清理C#2.0的匿名委託語法......例如
Strings.Find(s => s == "hello");
做C#2.0中是這樣的:
Strings.Find(delegate(String s) { return s == "hello"; });
功能上,他們做同樣的事情,它只是一個更簡潔的語法。
微軟爲我們提供了一種更簡潔,更便捷的創建名爲Lambda表達式的匿名委託的方法。然而,本聲明的部分內容表達式沒有多少關注。微軟發佈了一個完整的命名空間System.Linq.Expressions,其中包含用於基於lambda表達式創建表達式樹的類。表達式樹由表示邏輯的對象組成。例如,x = y + z是一個表達式,可能是.Net中表達式樹的一部分。考慮以下(簡單)示例:
using System;
using System.Linq;
using System.Linq.Expressions;
namespace ExpressionTreeThingy
{
class Program
{
static void Main(string[] args)
{
Expression<Func<int, int>> expr = (x) => x + 1; //this is not a delegate, but an object
var del = expr.Compile(); //compiles the object to a CLR delegate, at runtime
Console.WriteLine(del(5)); //we are just invoking a delegate at this point
Console.ReadKey();
}
}
}
此示例很簡單。我相信你在想:「這是無用的,因爲我可以直接創建委託,而不是創建表達式並在運行時編譯它。」你會是對的。但是這爲表達樹提供了基礎。 Expressions命名空間中有許多可用的表達式,您可以構建自己的表達式。我想你可以看到,當你不知道算法在設計或編譯時應該是什麼時,這可能是有用的。我在某個地方看到了使用它編寫科學計算器的例子。您也可以將它用於Bayesian系統或genetic programming(AI)。在我的職業生涯中,我不得不編寫類似Excel的功能,允許用戶輸入簡單的表達式(添加,刪除等)來操作可用數據。在pre.Net 3.5中,我不得不求助於C#外部的某種腳本語言,或者必須在反射中使用代碼發射功能來即時創建.Net代碼。現在我會使用表達式樹。
我發現它們在我想用另一個控件聲明某個控件事件的處理程序的情況下很有用。 要做到這一點,通常必須將控件的引用存儲在類的字段中,以便可以使用與創建方法不同的方法。
private ComboBox combo;
private Label label;
public CreateControls()
{
combo = new ComboBox();
label = new Label();
//some initializing code
combo.SelectedIndexChanged += new EventHandler(combo_SelectedIndexChanged);
}
void combo_SelectedIndexChanged(object sender, EventArgs e)
{
label.Text = combo.SelectedValue;
}
感謝lambda表達式,你可以使用它像這樣:
public CreateControls()
{
ComboBox combo = new ComboBox();
Label label = new Label();
//some initializing code
combo.SelectedIndexChanged += (s, e) => {label.Text = combo.SelectedValue;};
}
容易得多。
lambda表達式就像代替委託實例寫入的匿名方法。
delegate int MyDelagate (int i);
MyDelagate delSquareFunction = x => x * x;
考慮lambda表達式x => x * x;
The input parameter value is x (on the left side of =>)
The function logic is x * x (on the right side of =>)
lambda表達式的代碼可以是一個語句塊代替的表達。
x => {return x * x;};
例
注:Func
是預定義的通用委託。
Console.WriteLine(MyMethod(x => "Hi " + x));
public static string MyMethod(Func<string, string> strategy)
{
return strategy("Lijo").ToString();
}
參考
您也可以在編寫通用代碼來作用於你的方法使用lambda表達式。
例如:通用函數計算方法調用所用的時間。 (即在Action
這裏)
public static long Measure(Action action)
{
Stopwatch sw = new Stopwatch();
sw.Start();
action();
sw.Stop();
return sw.ElapsedMilliseconds;
}
你可以使用lambda表達式如下調用上面的方法,
var timeTaken = Measure(() => yourMethod(param));
表達允許你從你的方法,並從獲得的返回值PARAM以及
var timeTaken = Measure(() => returnValue = yourMethod(param, out outParam));
創新是在類型安全和透明。儘管您沒有聲明lambda表達式的類型,但它們被推斷出來,並且可以被代碼搜索,靜態分析,重構工具和運行時反射使用。
例如,在您可能使用過SQL並可能獲得SQL注入攻擊之前,因爲黑客傳遞了一個字符串,而該字符串通常是數字。現在你將使用一個LINQ lambda表達式,它受到保護。
在純代理上構建LINQ API是不可能的,因爲它需要在評估它們之前將表達式樹組合在一起。
2016年大多數流行語言都支持lambda expression,而C#是這種演進中主流命令式語言的先驅之一。
這也許是爲什麼使用lambda表達式最好的解釋 - >https://youtu.be/j9nj5dTo54Q
總之,它是提高代碼的可讀性,通過重複使用而不是複製代碼,並利用優化幕後的減少錯誤的機會。
如何定義Find()方法來處理這個lambda表達式? – 2008-10-03 15:16:51
謂詞是Find方法所期待的。 –
2008-10-03 15:19:28
由於我的lambda表達式與Predicate的契約匹配,Find()方法接受它。 –
2008-10-03 15:21:01