本筆記摘抄自:https://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html,記錄一下學習過程以備後續查用。 一、Lambda 的意義 在Framework 2.0 以前,聲明委托的唯一方法是通過方法命名,從Framework 2.0 ...
本筆記摘抄自:https://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html,記錄一下學習過程以備後續查用。
一、Lambda 的意義
在Framework 2.0 以前,聲明委托的唯一方法是通過方法命名,從Framework 2.0 起,系統開始支持匿名方法。通過匿名方法,可以直接把一段代碼綁定
給事件,因此減少了實例化委托所需的編碼系統開銷。而在 Framework 3.0 開始,Lambda表達式開始逐漸取代了匿名方法,作為編寫內聯代碼的首選方式。
總體來說,Lambda 表達式的作用是為了使用更簡單的方式來編寫匿名方法,徹底簡化委托的使用方式。
二、回顧匿名方法的使用
匿名方法的使用在C#委托與事件學習筆記中有簡單介紹過,在此回顧一下:
static void Main(string[] args) { #region 事件的使用及方法綁定 PersonManager personManager = new PersonManager(); //綁定事件處理方法方式一 personManager.MyEvent += new MyDelegate(GetName); //綁定事件處理方法方式二 personManager.MyEvent += GetName; //綁定事件處理方法方式三(匿名方法) personManager.MyEvent += delegate (string name) { Console.WriteLine("My name is " + name); }; personManager.Execute("Atomy"); Console.Read(); #endregion }View Code
總是使用 delegate(){......} 的方式建立匿名方法,令人不禁感覺鬱悶。於是從Framework 3.0起,Lambda表達式開始出現。
三、簡單介紹泛型委托
在介紹Lambda表達式前,先介紹一下常用的幾個泛型委托。
3.1 泛型委托 Predicate<T>
早在Framework 2.0的時候,微軟就為List<T>類添加了Find、FindAll、ForEach等方法用作數據的查找。
public T Find ( Predicate<T> match)
public List<T> FindAll(Predicate<T> match)
在這些方法中存在一個Predicate <T> 表達式,它是一個返回bool的泛型委托,能接受一個任意類型的對象作為參數。
public delegate bool Predicate<T>(T obj)
在下麵例子中,Predicate委托綁定了參數為Person類的方法Match作為查詢條件,然後使用FindAll方法查找到合適條件的List<Person>集合。
class Program { #region 泛型委托 Predicate<T> /// <summary> /// Person類 /// </summary> class Person { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public Person(int id, string name, int age) { Id = id; Name = name; Age = age; } } /// <summary> /// 數據源 /// </summary> /// <returns></returns> static List<Person> GetList() { var personList = new List<Person>(); var person = new Person(1, "Hello", 29); personList.Add(person); person = new Person(1, "World", 31); personList.Add(person); return personList; } /// <summary> /// 查詢條件 /// </summary> /// <param name="person"></param> /// <returns></returns> static bool Match(Person person) { return person.Age <= 30; } #endregion static void Main(string[] args) { #region 泛型委托 Predicate<T> List<Person> list = GetList(); //綁定查詢條件 Predicate<Person> predicate = new Predicate<Person>(Match); List<Person> result = list.FindAll(predicate); Console.WriteLine($"Person count is : {result.Count}"); Console.Read(); #endregion } }View Code
運行結果如下:
3.2 泛型委托 Action
Action<T> 的使用方式與 Predicate<T> 相似,不同之處在於 Predicate<T> 返回值為 bool , Action<T> 的返回值為 void。
Action 支持0~16個參數,可以按需求任意使用。
public delegate void Action()
public delegate void Action<T1> (T1 obj1)
public delegate void Action<T1,T2> (T1 obj1, T2 obj2)
public delegate void Action<T1,T2,T3> (T1 obj1, T2 obj2,T3 obj3)
............
public delegate void Action<T1,T2,T3,......,T16> (T1 obj1, T2 obj2,T3 obj3,......,T16 obj16)
下麵代碼演示泛型委托Action:
class Program { #region 泛型委托 Action static void ShowMessage(string message) { Console.WriteLine(message); } #endregion static void Main(string[] args) { #region 泛型委托 Action Action<string> action = ShowMessage; action("Hello World"); Console.ReadKey(); #endregion } }View Code
運行結果如下:
3.3 泛型委托 Func
委托Func與Action相似,同樣支持0~16個參數,不同之處在於Func必須具有返回值。
public delegate TResult Func<TResult>()
public delegate TResult Func<T1,TResult>(T1 obj1)
public delegate TResult Func<T1,T2,TResult>(T1 obj1,T2 obj2)
public delegate TResult Func<T1,T2,T3,TResult>(T1 obj1,T2 obj2,T3 obj3)
............
public delegate TResult Func<T1,T2,T3,......,T16,TResult>(T1 obj1,T2 obj2,T3 obj3,......,T16 obj16)
下麵代碼演示泛型委托Func:
class Program { #region 泛型委托 Func static double Account(double a, bool condition) { if (condition) return a * 1.5; else return a * 2; } #endregion static void Main(string[] args) { #region 泛型委托 Func Func<double, bool, double> func = Account; double result = func(1000, true); Console.WriteLine($"Result is : {result}"); Console.Read(); #endregion } }View Code
運行結果如下:
四、揭開 Lambda 神秘的面紗
Lambda的表達式的編寫格式如下:x=> x * 1.5
當中 “ => ”是Lambda表達式的操作符,在左邊用作定義一個參數列表,右邊可以操作這些參數。
例子一:先把int x設置1000,通過Action把表達式定義為x=x+500,最後通過Invoke激發委托。
class Program { static void Main(string[] args) { #region Lambda例子一 int x = 1000; Action action = () => x = x + 500; action.Invoke(); Console.WriteLine($"Result is : {x}"); Console.Read(); #endregion } }View Code
運行結果如下:
例子二:通過Action<int>把表達式定義x=x+500,到最後輸入參數1000,得到的結果與例子一相同。
註意,此處Lambda表達式定義的操作使用{ }括弧包括在一起,裡面可以包含一系列的操作。
class Program { static void Main(string[] args) { #region Lambda例子二 Action<int> action = (x) => { x = x + 500; Console.WriteLine($"Result is : {x}"); }; action.Invoke(1000); Console.Read(); #endregion } }View Code
運行結果如下:
例子三:定義一個Predicate<int>,當輸入值大約等於1000則返回true,否則返回false。與3.1的例子相比,Predicate<T>的綁定不需要顯式建立一個方法,
而是直接在Lambda表達式里完成,簡潔方便了不少。
class Program { static void Main(string[] args) { #region Lambda例子三 Predicate<int> predicate = (x) => { if (x >= 1000) return true; else return false; }; bool result = predicate.Invoke(500); Console.WriteLine($"Result={result}"); Console.Read(); #endregion } }View Code
運行結果如下:
例子四:在計算商品的價格時,當商品重量超過30kg則打9折,其他按原價處理。此時可以使用Func<double,int,double>,參數1為商品原價,參數2為商品
重量,最後返回值為 double 類型。
class Program { static void Main(string[] args) { #region Lambda例子四 Func<double, int, double> func = (price, weight) => { if (weight >= 30) return price * 0.9; else return price; }; double totalPrice = func(200.0, 40); Console.WriteLine($"TotalPrice={totalPrice}"); Console.Read(); #endregion } }View Code
運行結果如下:
例子五:使用Lambda為Button定義Click事件的處理方法,使用Lambda比使用匿名方法更加簡單。
public partial class Main : Form { public Main() { InitializeComponent(); } private void Main_Load(object sender, EventArgs e) { #region Lambda例子五 btnEvent.Click += (obj,arg)=> { MessageBox.Show("Hello World"); }; #endregion } }View Code
運行結果如下:
例子六:此處使用3.1的例子,在List<Person>的FindAll方法中直接使用Lambda表達式。相比之下,使用Lambda表達式,不需要定義Predicate<T>對象,也
不需要顯式設定綁定方法,簡化了不工序。
class Program { #region 泛型委托 Predicate<T> /// <summary> /// Person類 /// </summary> class Person { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public Person(int id, string name, int age) { Id = id; Name = name; Age = age; } } /// <summary> /// 數據源 /// </summary> /// <returns></returns> static List<Person> GetList() { var personList = new List<Person>(); var person = new Person(1, "Hello", 29); personList.Add(person); person = new Person(1, "World", 31); personList.Add(person); return personList; } /// <summary> /// 查詢條件 /// </summary> /// <param name="person"></param> /// <returns></returns> static bool Match(Person person) { return person.Age <= 30; } #endregion static void Main(string[] args) { #region Lambda例子六 List<Person> personList = GetList(); //查找年齡少於30年的人 List<Person> result = personList.FindAll((person) => person.Age <= 30); Console.WriteLine("Person count is : " + result.Count); Console.Read(); #endregion } }View Code
運行結果如下:
當在使用LINQ技術的時候,到處都會瀰漫著Lambda的身影,此時更能體現Lambda的長處。但LINQ涉及到分部類、分部方法、IEnumerable<T>、迭代器等
多方面的知識,這些已經超出本章的介紹範圍。通過這一節的介紹,希望能夠幫助大家更深入地瞭解Lambda的使用。