委托,lambda表达式和事件

来源:互联网 发布:php开发教程视频 编辑:程序博客网 时间:2024/06/04 17:43

要区分三者之间的联系与区别首先要明白它们的定义

什么是委托?

委托是类型安全的类,它定义了返回类型和参数类型。委托由关键字delegate来声明

什么情况使用委托?

当要把方法传送给其他方法是,需要使用委托。

既然委托是将方法作为参数传递它,那么委托与指针有什么联系?

委托是面向对象,是类型安全的。

在C++中,函数指针只不过是一个指向内存位置的指针,它不是类型安全的。

委托包含:普通委托,lambda表达式和匿名方法,事件

一、普通委托(单路委托,多播委托,泛型委托(Action<T>和Func<T>))

定义一个委托类的语法:

[访问限制符] delegate [返回值类型] [委托类的名称]( [参数列表] ); 
1.单路委托(单路委托就是和方法建立一对一的关系

2.多播委托(多播委托就是和方法建立一对多的关系

3.泛型委托

泛型Action<T>委托类表示引用一个void返回类型的方法

Func<T>委托的使用方式和Action<T>委托类似.Func<T>允许调用带有返回值的方法

二、匿名方法和lambda表达式

1.匿名方法(是用作委托的参数的一段代码)

用匿名方法定义委托的语法与前面的定义没有区别,但在实例化委托时有所区别,如下实例说明了如何使用匿名方法

static void Main()
{
string mid=",middle part,";
Func<string,string> anonDel=delegate(string param)
{
param +=mid;
param +="and this was added to the string.";
return param;
};//结尾的";"别忘记
Console.WriteLine(anonDel("Start of string"));
}

/*使用匿名委托的时,要遵守两个原则

1、匿名方法中不能有跳转语句(break, goto或continue)跳转到匿名方法的外部,反之,外部代码也不能跳转到该匿名方法内部。

2、在匿名方法中不能访问不安全代码。
注意:不能访问在匿名方法外部使用的ref和out参数。*/

2.Lambda表达式(只要有委托参数类型的地方,就可以使用Lambda表达式)

语法:

[委托类] [委托对象名] = ( [参数列表] ) => { /*代码块*/ };   //结尾还是有一个分号
将前面使用匿名方法的例子改为lambda表达式:
static void Main()
{
string mid=",middle part,";
Func<string,string> lambda=param=>
{
param +=mid;
param +="and this was added to the string.";
return param;
};//结尾的";"别忘记
Console.WriteLine(lambda("Start of string"));
}

三、事件

事件基于委托,为委托提供了一种发布/订阅机制。事件是一种特殊多播委托,换句话来说,事件是经过深度封装的委托。一个事件简单的可以看作一个多播委托加上两个方法(+=订阅消息和-=取消订阅)。

1、普通事件

        我们使用event关键字来声明事件,语法如下:

[访问权限修饰符] event [委托类类名] [名称];

事件一般是用于通知代码发生了什么。由此我们又可以引出两个概念:1、事件发布方2、事件侦听方。我们现在用一个简单的例子来说明这两个概念,我们以烧开水为例,当水温为95至100度时发出警报。我们先来定义在事件发生时,需要传输的数据成员:

public class Water//事件发布程序中的基本数据成员类{    public int Temperature { get; private set; }    public Water(int t)    {        this.Temperature = t;    }}

有了传输的数据,那么我们现在就可以定义事件触发类::

public delegate void WaterHandler(object sender, Water w);     //sender为事件发送者,w为发送的数据public class Heater//事件发布程序中的,事件触发类{    public event WaterHandler WaterEvent;    //深度的封装委托    public void HeatWater()//该方法用于触发事件    {        for (int i = 0; i < 101; i++)        {            if (i > 95 && i < 101)            {                RegWaterEvent(i);//触发事件            }        }    }    protected virtual void RegWaterEvent(int t)    {        WaterHandler temp = WaterEvent;        if (temp != null)            temp(this, new Water(t));//如果委托不为空,我们就执行委托,我们无需知道具体执行了哪些方法    }}

       现在我们已经完整了定义好了事件发布方了,通过这个例子我们也知道了事件发布方由两部分组成:1、基本数据类   2、事件触发类。接下来我们继续看看事件侦听方又是怎么样的:

public class Alarm//事件侦听类{    public void Waring(object sender, Water w)//侦听接口,由于侦听事件的发布    {        Console.WriteLine("当前水温已经到达 {0} ℃!", w.Temperature);    }}

      通过这个例子我们可以发现,事件侦听类,只需有一个和被监听事件一致的方法即可。

Heater heater = new Heater();//生成事件发布实例Alarm alarm = new Alarm();heater.WaterEvent += alarm.Waring;//对事件发布方进行订阅(侦听),反之我们使用-=取消订阅heater.HeatWater();//触发事件,那么现在Alarm类对象alarm将会侦听到这次事件

        通过上述例子我们就大致的了解了事件的工作情况,以及事件发布方和事件侦听方的概念。

       .Net平台为我们提供了泛型委托EventHandler<T>,有了这个泛型委托之后我们就不在需要定义委托类了。我们来看看泛型委托EventHandler<T>的原型:

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e)where TEventArgs: EventArgs;
       参数列表中第一个参数是对象,包含事件的发送者,第二个参数提供了事件的相关信息。现在我们定义事件时,只需让基本数据类继承EventArgs,然后我们就能泛型委托来定义事件了。
注意:事件只能在本类型内部“触发”,委托不管在本类型内部还是外部都可以“调用”。事件在类的外部只能使用+=或-=来增加/取消订阅


0 0
原创粉丝点击