一起谈.NET技术,C# 委托,事件和Lambda表达式

简介:   关于这个论题,Delegates, Events, and Lambda Expressions 对此有比较深入的分析,可以参考。C# vs C++之一:委托 vs 函数指针 比较了委托和C++指针的区别。

  关于这个论题,Delegates, Events, and Lambda Expressions 对此有比较深入的分析,可以参考。C# vs C++之一:委托 vs 函数指针 比较了委托和C++指针的区别。

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

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

delegate int Echo(string message);

  这句代码声明了一个委托类型,这个委托类型的实例可以接受参数为string,返回值为int型的函数。这个方法可以是对象的方法,也可以静态方法,还可以是匿名方法,只要方法的签名和返回值是和声明一致的。这和C的函数指针很像,但是函数指针仅仅包含函数入口地址,而委托是一个类型,它具有比函数指针更强的功能。其中一点就是当方法是实例方法的时候,这个方法可以获得对象的其他变量的值,文首的第二篇文章对此有详细介绍,不再赘述。第二点就是委托是支持多播的,也就是一串方法可以可以依次被执行。例如:

static int EchoOriginal(string message)
{
Console.WriteLine(message);
return 1;
}

static int EchoReverse(string message)
{
StringBuilder sb=new StringBuilder();
for(int i=message.Length-1;i>=0;i--)
sb.Append(message[i]);
Console.WriteLine(sb.ToString());
return -1;
}

static void Main(string[] args)
{
Echo eo = EchoOriginal;
Echo er = EchoReverse;
Echo all = eo + er;
eo("Hello world");
int i=all("Hello Delegate");
Console.WriteLine(i);
}

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

  Hello world
  Hello Delegate
  etageleD olleH
  -1

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

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

 public delegate void EventHandler(
Object sender, EventArgs e )

  声明事件的基本方式是 event 委托类型事件名称;

  举个例子,有这样的类,每当找到一个奇数,他就会触发一个事件。我们的程序在接到这个事件的时候在屏幕输出一个提示。类的代码可以这样实现:

public class OddFinder
{
public event EventHandler FindOdd;

public void Find(int from, int to)
{
for (int i = from; i <= to; i++)
{
if (i % 2 != 0)
if (FindOdd != null)
FindOdd(this, EventArgs.Empty);
}
}
}

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

static void Main(string[] args)
{
OddFinder f = new OddFinder();
f.FindOdd += new EventHandler(f_FindOdd);
f.Find(1, 5);
}

static void f_FindOdd(object sender, EventArgs e)
{
Console.WriteLine("Found!");
}

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

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

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

  匿名方法使用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关键字,使得代码更加紧凑。例如:

 
 
n => n % 2 == 0 ;

  等价于:

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

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

目录
相关文章
|
3月前
|
开发框架 .NET 编译器
C# 10.0中Lambda表达式的改进:更简洁、更灵活的代码编写体验
【1月更文挑战第21天】随着C#语言的不断发展,Lambda表达式作为一种简洁、高效的函数式编程工具,在C# 10.0中迎来了重要的改进。本文将详细探讨C# 10.0中Lambda表达式的新特性,包括参数类型的推断增强、自然类型的Lambda参数以及Lambda表达式的属性改进等。这些改进不仅简化了Lambda表达式的编写过程,还提升了代码的可读性和灵活性,为开发者带来了更优质的编程体验。
|
7月前
|
Java 编译器 C#
C#中的Lambda表达式
C#中的Lambda表达式
44 0
|
3月前
|
机器学习/深度学习 开发框架 .NET
C# 中的 Lambda 表达式:一种简洁而强大的编程工具
【1月更文挑战第6天】在现代编程中,Lambda 表达式已经成为一种非常流行的编程范式。C# 作为一种功能强大的、面向对象的编程语言,自然也不例外。Lambda 表达式在 C# 中提供了一种简洁、灵活的方式来表示匿名函数。这些函数可以被用作委托或表达式树类型,从而在各种不同的上下文中使用。
|
4月前
|
Java C# C++
【从Java转C#】第八章:委托、lambda、事件
【从Java转C#】第八章:委托、lambda、事件
|
4月前
|
C#
C# Lambda
C# Lambda
21 0
|
9月前
|
开发框架 .NET 编译器
C# Lambda表达式和linq表达式 之 匿名对象查询接收
C# Lambda表达式和linq表达式 之 匿名对象查询接收
|
12月前
|
缓存 前端开发 JavaScript
采用.Net Core技术框架开发的医院云LIS平台源码,B/S架构
基于B/S架构的医学实验室检验系统源码,整个系统的运行基于WEB层面,只需要在对应的工作台安装一个浏览器软件有外网即可访问。全套系统采用云部署模式,部署一套可支持多家医院检验科共同使用。 采用.Net Core新的技术框架、DEV报表、前端js封装、分布式文件存储、分布式缓存等,支持LIS独立部署,Docker部署等多种方式。
|
编译器 C#
C#——Lambda表达式
C#——Lambda表达式
74 0
|
编译器 C# C语言
C#技巧:常用的lambda表达式整理
"Lambda表达式"属于一个匿名函数,是一种针对C\#编程语言高效的类似于函数式编程的表达式。采用Lambda简化了匿名委托的使用,可以大大减少开发中需要编写的代码量。比如针对一些求和、去重、排序等等可以省去了循环遍历的写法,使得代码变得更加简洁。
C#技巧:常用的lambda表达式整理
|
1月前
|
C#
24. C# 编程:用户设定敌人初始血值的实现
24. C# 编程:用户设定敌人初始血值的实现
18 0