引言

本章将介绍Predicate、Action、Func多种泛型委托的使用和Lambda的发展过程与其使用方式。

 

目录

一、委托类型的来由

二、建立委托类

三、委托使用方式

四、深入解析事件

五、Lambda 表达式

 

五、Lambda 表达式

5.1 Lambda 的意义

在Framework 2.0 以前,声明委托的唯一方法是通过方法命名,从Framework 2.0 起,系统开始支持匿名方法。
通过匿名方法,可以直接把一段代码绑定给事件,因此减少了实例化委托所需的编码系统开销。
而在 Framework 3.0 开始,Lambda 表达式开始逐渐取代了匿名方法,作为编写内联代码的首选方式。总体来说,Lambda 表达式的作用是为了使用更简单的方式来编写匿名方法,彻底简化委托的使用方式。

 

5.2 回顾匿名方法的使用

匿名方法的使用已经在4.4节简单介绍过,在此回顾一下。
使用下面的方式,可以通过匿名方法为Button的Click事件绑定处理方法。

1         static void Main(string[] args)
2         {
3             Button btn = new Button();
4             btn.Click+=delegate(object obj,EventArgs e){
5                 MessageBox.Show("Hello World !");
6             };
7         }

总是使用 delegate(){......} 的方式建立匿名方法,令人不禁感觉郁闷。于是从Framework 3.0 起, Lambda 表达式开始出现。

 

5.3 简单介绍泛型委托

在介绍 Lambda 表达式前,先介绍一下常用的几个泛型委托。

 

5.3.1 泛型委托 Predicate

早在Framework 2.0 的时候,微软就为 List 类添加了 Find、FindAll 、ForEach 等方法用作数据的查找。

public T Find ( Predicate match)
public List FindAll(Predicate  match)

在这些方法中存在一个Predicate 表达式,它是一个返回bool的泛型委托,能接受一个任意类型的对象作为参数。

public delegate bool Predicate(T obj)

在下面例子中,Predicate 委托绑定了参数为Person类的方法Match作为查询条件,然后使用 FindAll 方法查找到合适条件的 List 集合。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             List list = GetList();
 6             //绑定查询条件
7 Predicate predicate = new Predicate(Match); 8 List result = list.FindAll(predicate); 9 Console.WriteLine(“Person count is : ” + result.Count); 10 Console.ReadKey(); 11 } 12 //模拟源数据
13 static List GetList() 14 { 15 var personList = new List(); 16 var person1 = new Person(1,"Leslie",29); 17 personList.Add(person1); 18 ........ 19 return personList; 20 } 21 //查询条件
22 static bool Match(Person person) 23 { 24 return person.Age <= 30; 25 } 26 } 27 28 public class Person 29 { 30 public Person(int id, string name, int age) 31 { 32 ID = id; 33 Name = name; 34 Age = age; 35 } 36 37 public int ID 38 { get; set; } 39 public string Name 40 { get; set; } 41 public int Age 42 { get; set; } 43 }

 

5.3.2 泛型委托 Action

Action 的使用方式与 Predicate 相似,不同之处在于 Predicate 返回值为 bool ,  Action 的返回值为 void。
Action 支持0~16个参数,可以按需求任意使用。

public delegate void Action()
public delegate void Action(T1 obj1)
public delegate void Action (T1 obj1, T2 obj2)
public delegate void Action (T1 obj1, T2 obj2,T3 obj3)
............
public delegate void Action (T1 obj1, T2 obj2,T3 obj3,......,T16 obj16)

 1         static void Main(string[] args)
 2         {
 3             Action<string> action=ShowMessage;
 4             action("Hello World");
 5             Console.ReadKey();
 6         }
 7 
 8         static void ShowMessage(string message)
 9         {
10             MessageBox.Show(message);
11         }

 

5.3.3 泛型委托 Func

委托 Func 与 Action 相似,同样支持 0~16 个参数,不同之处在于Func 必须具有返回值

public delegate TResult Func()
public delegate TResult Func(T1 obj1)
public delegate TResult Func(T1 obj1,T2 obj2)
public delegate TResult Func(T1 obj1,T2 obj2,T3 obj3)
............
public delegate TResult Func(T1 obj1,T2 obj2,T3 obj3,......,T16 obj16)

 1         static void Main(string[] args)
 2         {
 3             Func<double, bool, double> func = Account;
 4             double result=func(1000, true);
 5             Console.WriteLine("Result is : "+result);
 6             Console.ReadKey();
 7         }
 8 
 9         static double Account(double a,bool condition)
10         {
11             if (condition)
12                 return a * 1.5;
13             else
14                 return a * 2;
15         }

 

5.4 揭开 Lambda 神秘的面纱

Lambda 的表达式的编写格式如下:

     x=> x * 1.5

当中 “ => ” 是 Lambda 表达式的操作符,在左边用作定义一个参数列表,右边可以操作这些参数。

例子一, 先把 int x 设置 1000,通过 Action 把表达式定义为 x=x+500 ,最后通过 Invoke 激发委托。

1         static void Main(string[] args)
2         {
3             int x = 1000;
4             Action action = () => x = x + 500;
5             action.Invoke();
6 
7             Console.WriteLine("Result is : " + x);
8             Console.ReadKey();
9         }


例子二,通过 Action 把表达式定义 x=x+500, 到最后输入参数1000,得到的结果与例子一相同。
注意,此处Lambda表达式定义的操作使用 { } 括弧包括在一起,里面可以包含一系列的操作。

 1         static void Main(string[] args)
 2         {
 3             Action<int> action = (x) =>
 4             {
 5                 x = x + 500;
 6                 Console.WriteLine("Result is : " + x);
 7             };
 8             action.Invoke(1000);
 9             Console.ReadKey();
10         }

 

例子三,定义一个Predicate,当输入值大约等于1000则返回 true , 否则返回 false。与5.3.1的例子相比,Predicate的绑定不需要显式建立一个方法,而是直接在Lambda表达式里完成,简洁方便了不少。

 1         static void Main(string[] args)
 2         {
 3             Predicate<int> predicate = (x) =>
 4             {
 5                 if (x >= 1000)
 6                     return true;
 7                 else
 8                     return false;
 9             };
10             bool result=predicate.Invoke(500);
11             Console.ReadKey();
12         }

 

例子四,在计算商品的价格时,当商品重量超过30kg则打9折,其他按原价处理。此时可以使用Func,参数1为商品原价,参数2为商品重量,最后返回值为 double 类型。

 1         static void Main(string[] args)
 2         {
 3             Func<double, int, double> func = (price, weight) =>
 4             {
 5                 if (weight >= 30)
 6                     return price * 0.9;
 7                 else
 8                     return price;
 9             };
10             double totalPrice = func(200.0, 40);
11             Console.ReadKey();
12         }


例子五,使用Lambda为Button定义Click事件的处理方法。与5.2的例子相比,使用Lambda比使用匿名方法更加简单。

1         static void Main(string[] args)
2         {
3             Button btn = new Button();
4             btn.Click += (obj, e) =>
5             {
6                 MessageBox.Show("Hello World!");
7             };
8             Console.ReadKey();
9         }


例子六,此处使用5.3.1的例子,在List的FindAll方法中直接使用Lambda表达式。
相比之下,使用Lambda表达式,不需要定义Predicate对象,也不需要显式设定绑定方法,简化了不工序。

 1      class Program
 2      {
 3         static void Main(string[] args)
 4         {
 5             List personList = GetList();
 6             
7 //查找年龄少于30年的人 8 List result=personList.FindAll((person) => person.Age =< 30); 9 Console.WriteLine("Person count is : " + result.Count); 10 Console.ReadKey(); 11 } 12 13 //模拟源数据
14 static List GetList() 15 { 16 var personList = new List(); 17 var person1 = new Person(1,"Leslie",29); 18 personList.Add(person1); 19 ....... 20 return personList; 21 } 22 } 23 24 public class Person 25 { 26 public Person(int id, string name, int age) 27 { 28 ID = id; 29 Name = name; 30 Age = age; 31 } 32 33 public int ID 34 { get; set; } 35 public string Name 36 { get; set; } 37 public int Age 38 { get; set; } 39 }


当在使用LINQ技术的时候,到处都会弥漫着 Lambda 的身影,此时更能体现 Lambda 的长处。
但 LINQ 涉及到分部类,分部方法,IEnumerable,迭代器等多方面的知识,这些已经超出本章的介绍范围。
通过这一节的介绍,希望能够帮助大家更深入地了解 Lambda 的使用。

 回到目录

本章小结

本章主要介绍了委托(Delegate)的使用,委托对象是一个派生自 System.MultcastDelegate 的类,它能通过 Invoke 方式进行同步调用,也可以通过 BeginInvoke,EndInvoke 方式实现异步调用。而事件(Event)属于一种特殊的委托,它与委托类型同步使用,可以简化的开发过程。
最后,本文还介绍了匿名方法的使用方式,以及 Lambda 表达式的由来。
希望本篇文章对相关的开发人员有所帮助。对JAVA与.NET开发有兴趣的朋友欢迎加入QQ群:162338858

 

C#综合揭秘

细说进程、应用程序域与上下文
细说多线程(上)

细说多线程(下)
细说事务
深入分析委托与事件