解析C#委托、时间和Lambda表达式

开发 后端
.NET 中的委托确实和C/C++的函数指针非常相似。它是一个值类型,它包装了一个指向方法的引用。来看本文,希望对你有帮助。

.NET 中的委托确实和C/C++的函数指针非常相似。它是一个值类型,它包装了一个指向方法的引用。它的作用也是为了能够将方法和变量一样作为参数传递。委托的典型应用是控件的事件处理方法。很显然,一个控件在设计的时候没有办法知道当特定事件发生的时候,需要什么方法来处理,这就需要将方法作为参数传递给控件。在LINQ中,也大量用到了委托。

声明一个委托要使用delegate关键字,如下:

delegate int Echo(string message);这句代码声明了一个委托类型,这个委托类型的实例可以接受参数为string,返回值为int型的函数。这个方法可以是对象的方法,也可以静态方法,还可以是匿名方法,只要方法的签名和返回值是和声明一致的。这和C的函数指针很像,但是函数指针仅仅包含函数入口地址,而委托是一个类型,它具有比函数指针更强的功能。

其中一点就是当方法是实例方法的时候,这个方法可以获得对象的其他变量的值,文首的第二篇文章对此有详细介绍,不再赘述。第二点就是委托是支持多播的,也就是一串方法可以可以依次被执行。例如:

以下是代码片段:

  1. static int EchoOriginal(string message)   
  2. { Console.WriteLine(message);   
  3. return 1; }   
  4. static int EchoReverse(string message)   
  5. {   
  6. StringBuilder sb=new StringBuilder();   
  7. for(int i=message.Length-1;i>=0;i--)   
  8. sb.Append(message[i]);   
  9. Console.WriteLine(sb.ToString());   
  10. return -1; }   
  11. static void Main(string[] args)   
  12. {   
  13. Echo eo = EchoOriginal;   
  14. Echo er = EchoReverse;   
  15. Echo all = eo + er;   
  16. eo("Hello world");   
  17. int i=all("Hello Delegate");   
  18. Console.WriteLine(i);   

 

我们定义两个方法,这两个方法都符合Echo的声明,***Echo的all实例可以接受两个委托,调用all的时候,eo,er会被一次钓鱼,返回值是***一个委托的返回值。程序的输出是:

Hello world

Hello Delegat

etageleD olleH

-1

事实上,方法并不需要和委托声明类型的签名完全一致,.net允许方法的返回值是继承自声明的返回值的类型,方法的参数类型是声明的参数的父类型。这就是Covariance and Contravariance in Delegates.

.NET的事件机制是以委托为基础的。事件机制有两部分组成,一部分是事件发布者,一部分是事件响应者。其实现原理就是由事件发布者声明一个委托对象,由事件响应者向那个委托挂载具体的处理方法,事件发布者在需要的时候调用这个委托,这样响应者的代码就会被执行。事实上,.NET也是这么做的。C#的event关键字就仅仅做了少量的工作,其中包括为类生成一个私有的delegate. event所支持的委托是有限制的委托,它的返回值必须是void,参数是两个,***个是事件发生者,第二个参数是事件需要携带的参数。最简单的事件处理委托.net已经声明了:

以下是代码片段:

  1. public delegate void EventHandler(   
  2. Object sender, EventArgs e ) 

 

声明事件的基本方式是 event 委托类型 事件名称;举个例子,有这样的类,每当找到一个奇数,他就会触发一个事件。我们的程序在接到这个事件的时候在屏幕输出一个提示。类的代码可以这样实现:

以下是代码片段:

  1. public class OddFinder {   
  2. public event EventHandler FindOdd;   
  3. public void Find(int from, int to)   
  4. {   
  5. for (int i = from; i <= to; i++)   
  6. {   
  7. if (i % 2 != 0) if (FindOdd != null)   
  8. FindOdd(this, EventArgs.Empty);   
  9. }   
  10. }   

 

这个类很简单,展示了发起事件的基本方法。首先声明一个事件,指明这个事件处理函数的委托类型。在需要触发事件的时候,首先判断是否有事件处理函数挂载,然后调用这个委托即可。外部处理程序把事件处理程序挂载上去:

以下是代码片段:

  1. static void Main(string[] args)   
  2. {   
  3. OddFinder f = new OddFinder();   
  4. f.FindOdd += new EventHandler(f_FindOdd);   
  5. f.Find(1, 5);   
  6. }   
  7. static void f_FindOdd(object sender, EventArgs e)   
  8. {   
  9. Console.WriteLine("Found!");   

 

这样程序运行后,就会在屏幕上输出3次Found!。如果需要在触发事件的时候,传递更多的信息给事件处理函数,比如当前找到的奇数是多少,那么就需要新建一个类继承自EventArgs,在这个类中可以添加一些需要的数据。 再声明一个委托,第二个参数为EventArgs类型即可。

以上是基本的委托和事件的介绍,自.net 1.0开始就是如此,.net 2.0 引入了匿名方法,可以简化委托的某些操作。例如:

以下是代码片段:

  1. f.FindOdd += delegate(object sender, EventArgs e)   
  2. {   
  3. Console.WriteLine("Found!");   
  4. }; 

 

匿名方法使用delegate关键字加上参数表,***是代码块来定义。它可以作为委托赋值给委托类型。它可以省去单独定义一个方法的麻烦。

.NET 3.0之后引入了Lambda表达式,它进一步简化了匿名方法的写法,使得在C#中,把函数作为参数传递变得更加简单自然,从而C#变得更加具有函数式语言的味道。关于函数式语言的进一步介绍,可以参考:Functional Programming Languages . 函数式语言的理论基础是Lambda Calulus,关于此可以参考A Tutorial Introduction to the Lambda Calculus .

Lambda表达式本质上还是匿名方法,它的一般形式是:

(input parameters) => expression左侧是参数列表,=>右侧是方法体,可以是一个表达式(expression lambda),也可以是大括号括起来的语句段(statement lambda)。它省略了delegate关键字,使得代码更加紧凑。例如:

 

  1. n=>n%2==0; 

 

等价于

 

  1. delegate(int n){ return n%2==0;} 

 

expression lambda 广泛应用于LINQ,它可以用来构造Expression Tree,Expression Tree是LINQ的基础。可以通过动态构造Expression Tree来实现复杂的动态LINQ查询,不过这种方法虽然通用,对于数据库查询,使用起来和传统的拼接字符串相比还是很麻烦。

【编辑推荐】

  1. 详解ADO.NET学习和使用方法
  2. Delphi基础 回调函数及其使用
  3. 详解VB.NET变量声明的方法
  4. 解析.NET中容易混淆的委托与接口
  5. 盘点VB.NET对话框制作技巧 
责任编辑:于铁 来源: IY专家网博客
相关推荐

2010-09-14 14:05:42

C#委托

2009-08-27 09:44:59

C# Lambda表达

2009-08-27 09:57:50

C# Lambda表达

2009-08-26 16:17:23

C# Lambda表达

2009-08-10 09:41:07

.NET Lambda

2024-03-25 13:46:12

C#Lambda编程

2021-08-31 07:19:41

Lambda表达式C#

2009-07-09 09:51:07

Lambda表达式C#

2009-09-14 13:57:20

C# Lambda表达Lambda表达式

2010-10-19 10:03:02

Lambda表达式

2022-11-07 07:11:19

C#lambda函数

2009-09-17 09:09:50

Lambda表达式Linq查询

2009-08-07 15:41:39

C#正规表达式

2009-07-01 09:56:10

C#3.0

2020-10-16 06:40:25

C++匿名函数

2009-09-11 09:48:27

Linq Lambda

2023-11-02 08:25:58

C++Lambda

2009-05-22 09:48:07

表达式树泛型委托.NET

2009-09-15 15:18:00

Linq Lambda

2009-09-09 13:01:33

LINQ Lambda
点赞
收藏

51CTO技术栈公众号