C#综合揭秘——深入分析委托与事件(下)

简介:

引言

本章将介绍Predicate<T>、Action<T>、Func<T,TResult>多种泛型委托的使用和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<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> 集合。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             List<Person> list = GetList();
 6             //绑定查询条件
7 Predicate<Person> predicate = new Predicate<Person>(Match); 8 List<Person> result = list.FindAll(predicate); 9 Console.WriteLine(“Person count is : ” + result.Count); 10 Console.ReadKey(); 11 } 12 //模拟源数据
13 static List<Person> GetList() 14 { 15 var personList = new List<Person>(); 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<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)

 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<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)

 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<int> 把表达式定义 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<int>,当输入值大约等于1000则返回 true , 否则返回 false。与5.3.1的例子相比,Predicate<T>的绑定不需要显式建立一个方法,而是直接在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<double,int,double>,参数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<Person>的FindAll方法中直接使用Lambda表达式。
相比之下,使用Lambda表达式,不需要定义Predicate<T>对象,也不需要显式设定绑定方法,简化了不工序。

 1      class Program
 2      {
 3         static void Main(string[] args)
 4         {
 5             List<Person> personList = GetList();
 6             
7 //查找年龄少于30年的人 8 List<Person> result=personList.FindAll((person) => person.Age =< 30); 9 Console.WriteLine("Person count is : " + result.Count); 10 Console.ReadKey(); 11 } 12 13 //模拟源数据
14 static List<Person> GetList() 15 { 16 var personList = new List<Person>(); 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<T>,迭代器等多方面的知识,这些已经超出本章的介绍范围。
通过这一节的介绍,希望能够帮助大家更深入地了解 Lambda 的使用。

 回到目录

本章小结

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

 

C#综合揭秘

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

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

本文转自 leslies2  51CTO博客,原文链接:http://blog.51cto.com/79100812/843501



相关文章
|
23天前
|
C#
c# Gridview 点击checkbox 触发的事件
c# Gridview 点击checkbox 触发的事件
|
11天前
|
安全 算法 测试技术
C#编程实战:项目案例分析
【4月更文挑战第20天】本文以电子商务系统为例,探讨C#在实际项目中的应用。通过面向对象编程实现组件抽象和封装,确保代码的可维护性和可扩展性;利用安全性特性保护用户数据;借助数据库操作处理商品信息;通过逻辑控制和算法处理订单;调试工具加速问题解决,展现C#的优势:面向对象、数据库交互、数据安全和开发效率。C#在实际编程中展现出广泛前景。
|
23天前
|
C#
C# Dev解决gridview1_SelectionChanged和gridview1_RowCellClick事件触发两次等问题
C# Dev解决gridview1_SelectionChanged和gridview1_RowCellClick事件触发两次等问题
C# Dev解决gridview1_SelectionChanged和gridview1_RowCellClick事件触发两次等问题
|
23天前
|
C#
C# 禁止ComboBox滚动事件细谈
C# 禁止ComboBox滚动事件细谈
|
2月前
|
开发框架 安全 .NET
C# .NET面试系列三:集合、异常、泛型、LINQ、委托、EF!
<h2>集合、异常、泛型、LINQ、委托、EF! #### 1. IList 接口与 List 的区别是什么? IList 接口和 List 类是C#中集合的两个相关但不同的概念。下面是它们的主要区别: <b>IList 接口</b> IList 接口是C#中定义的一个泛型接口,位于 System.Collections 命名空间。它派生自 ICollection 接口,定义了一个可以通过索引访问的有序集合。 ```c# IList 接口包含一系列索引化的属性和方法,允许按索引访问、插入、移除元素等。 由于是接口,它只定义了成员的契约,而不提供具体的实现。类似于 IEnumera
159 2
|
4月前
|
存储 C# C++
C#进阶-委托(Delegrate)
类似于 C 或 C++ 中函数的指针,委托是C#的函数指针,是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。本篇文章我们将讲解C#里委托的类型及如何使用。委托的语法第一次接触难免感到陌生,最好的学习方式就是在项目中多去使用,相信会有很多感悟。
27 0
|
5月前
|
Java C# C++
【从Java转C#】第八章:委托、lambda、事件
【从Java转C#】第八章:委托、lambda、事件
|
5月前
|
C#
C#中的委托
C#中的委托
20 0
|
6月前
|
存储 开发框架 .NET
c#委托详解
委托是一种能够将方法作为参数传递、存储方法并且调用方法的类型,它可以让我们写出更加灵活和可扩展的代码。委托通常用于回调 (Callback) 机制,比如在事件处理、异步编程、LINQ 查询等场景中常常会使用委托。它可以将方法作为参数传递给其他方法,从而在需要的时候执行该方法。
28 2