知识点目录==========>传送门

首先推荐两篇大牛写的委托和事件的博客,写的超级好!看了就包你看会,想学习的朋友直接看这两篇就足以,我自己写的是算是自己学习的纪录。

传送门==========》C# 中的委托和事件

                    C# 中的委托和事件续

委托是什么?

委托是一个类,它定义了一种的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。

--摘自百度百科。

说白了委托和我们平常常见的类是差不多的东西。它也是一个类型,一个对象。委托定义类似定义一种方法模板。满足于这个模板的任何方法都可以赋值于委托。并且将这个委托当参数进行传递,进而把方法当参数传递。

    public delegate void deTest(string name);

这就定义个没有返回值的委托。定义委托需要关键字 delegate,这个关键字和我们定义的class关键字是一样的,记住是这样定义的就好了,下面部分就和定义方法的声明是一样的。去掉delegate关键,就是和定义方法一模一样。

只要满足没有返回值,而且参数是string类型的参数的方法都满足于这个委托。都可以赋值绑定给这个委托。还是上面那句话.定义委托就等于声明了一个方法的模板。

接下来就演示下委托如何使用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace 委托和事件
{
public delegate void deTest(string name);
public class Test
{
public void SayHello(string name, deTest test)
{
test(name);
}
}
}

首先看委托是定义在类外面的,说明定义类的地方都可以定义委托,委托和类是平级关系的。

Test类里面有个SayHello方法。这个方法有两个参数。一个就是string类型的参数,一个是委托类型的参数。委托类型的参数是什么意思呢?意思就是将满足委托模板的方法,将方法当作参数传递。因为没有委托方法是无非当参数传递的,最后SayHello方法里面调用这个委托。因为这个委托参数本身也是方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace 委托和事件
{ class Program
{
static void Main(string[] args)
{ Test t1 = new Test();
deTest detest = SayHelloByEngilsh;
t1.SayHello("小明",detest);
} public static void SayHelloByEngilsh(string name)
{
Console.WriteLine(string.Format("Hello{0}", name));
}
}
}

首先我们有一个SayHelloByEnglish的方法。这个方法正好满足我们这个委托模板,无返回值,有一个string类型的参数。Main函数里将这个方法赋值于我们定义的委托。然后将这个委托传递到我们test的SayHello方法里面。

这个例子并不适合使用委托,不是一个好的使用委托的场景,在这里面写主要是为了大家了解委托如何创建使用。现在我们在重新梳理一下。首先我们定义了一个Test类,在类里面有个SayHello方法。这个方法有两个参数对吧。

一个是string类型,一个是委托类型。方法面执行这个委托。因为委托本身就是绑定的方法,值就是方法,所以可以让方法直接调用。接下来是main函数里面真正的调用。将一个满足委托的方法赋值于委托,然后传递给了这个方法。最后方法内部执行的委托的时候,其实是执行了我们绑定的方法。也就是SayHelloTest。一个委托创建使用的demo就结束了。

总结下委托

委托赋值语发是+

绑定语法是+=

解绑语法是-=

下面来演示下委托的应用场景,现在我们有个需求,有一个热水器,热水器连接着显示器,和报警器。热水器温度达到80°的时候,显示器就会显示提示,报警器就会报警。先用正常方法实现下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace 委托和事件
{
public class WaterHeater
{
int temperature = ;
public void BoilWater()
{
for (int i = ; i < ; i++)
{
temperature++;
}
//报警器报警
//显示器报警
}
}
}

这里就定义个热水器类,这个类就是一个烧水的类。类里面温度一直再加,到了80就开始报警了。报警的操作占时没写。下面就开定义报警类。和显示器类。

    public class Monitor
{
public void ShowMessage(int temperature)
{
Console.WriteLine(string.Format("热水器在的温度已经{0}°啦,赶紧去洗澡吧", temperature));
}
}
public class Alarm
{
public void Police(int temperature)
{
Console.WriteLine(string.Format("热水器在的温度已经{0}°啦,赶紧去洗澡吧", temperature));
}
}

这个就是显示器类和烧水类。两个类的东西一样,只有一个简单的报警方法。接下来就是将热水器到了80°之后的报警操作补全。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace 委托和事件
{
public class WaterHeater
{
int temperature = ;
public void BoilWater()
{
for (int i = ; i < ; i++)
{
temperature++;
}
//报警器报警
Monitor monitor = new Monitor();
Alarm alarm = new Alarm();
monitor.ShowMessage(temperature);
alarm.Police(temperature);//显示器报警
  } }
}

这地方就是new了报警器和显示器的对象。然后调用两个对象的报警方法。功能已经实现了。但是这个地方有问题。写的很low,看到两个new我们就应该知道这个地方又是强耦合。不利于需求变动。万一哪天我们新加了一个别的报警装置。我还们还要修改这个热水器烧水的方法。设计的很不好。大家想想这个地方无非是要在温度到了80°之后执行显示器和报警器里面的报警方法。我们刚刚讲过的委托就是可以和方法绑定。那这个地方我们可不可以让热水器暴露一个委托变量,热水器温度达到80°之后。调用这个委托变量。委托的绑定放在外面。这样的话。就将高耦合变成了没有耦合,或者说是低耦合。如果没有明白的话。看一手代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace 委托和事件
{
  //定义委托
public delegate void Prompt(int temperature);
public class WaterHeater
{
    //声明委托变量
public Prompt promt;
public int temperature = ;
public void BoilWater()
{
for (int i = ; i < ; i++)
{
temperature++;
}
promt(temperature);
}
}
}

这个地方我们定义了一个委托,修改WaterHeater类声明了一个这个委托的变量。这个地方我改为调用这个委托变量用来取代原来的与报警器和显示器的关联,将之前的高耦合进行解耦。现在这个类已经和报警器没有一点关联。但是不能没有一点关联的对吧。不然怎么调用是吧。接下演示绑定的地方。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace 委托和事件
{ class Program
{
static void Main(string[] args)
{
Monitor monitor = new Monitor();
Alarm alarm = new Alarm();
WaterHeater waterHeater = new WaterHeater();
waterHeater.promt = monitor.ShowMessage;//委托绑定
waterHeater.promt += alarm.Police;//委托绑定
waterHeater.BoilWater();
} }
}

我们在main方法里面进行对委托的绑定。我们将之前在类的内部的强耦合提到了外面。如果不需要某个报警装置了,或者我们要添加某个装置。只要在main方法对委托进行绑定,或者解绑就好了。不需要再去修改热水器烧水的代码了。到这里委托的基本使用就介绍完了,下面介绍下事件。

事件是什么? 事件就是对委托的封装。举个例子,属性封装了字段。事件就是等于对委托的封装。有了事件我赋值可以直接使用+=或者-=而不需要用+。

下面演示一波事件代码。将之前的代码进行修改。

namespace 委托和事件
{
public delegate void Prompt(int temperature);
public class WaterHeater
{
private Prompt promt;
public event Prompt OnPromptEvent;//定义Prompt委托类型的事件。
public int temperature = ;
public void BoilWater()
{
for (int i = ; i < ; i++)
{
temperature++;
}
        //调用事件
OnPromptEvent(temperature);
}
}

这个地方我们又声明了一个事件。并且将调用委托的地方改为了事件,还将委托的访问类型改为私有。main方法我们也进行了修改。

事件小总结

1.声明关键字 event

2.关键字后面紧跟委托类型

修改main方法

        static void Main(string[] args)
{
Monitor monitor = new Monitor();
Alarm alarm = new Alarm();
WaterHeater waterHeater = new WaterHeater();
waterHeater.OnPromptEvent += monitor.ShowMessage;
waterHeater.OnPromptEvent += alarm.Police;
waterHeater.BoilWater();
}

将委托的绑定改为了事件绑定。到了这里有没有同学发现和我们winform 按钮事件是极为相似的,其实按钮那个点击事件也是这个事件。

   this.button1.Click += new System.EventHandler(this.button1_Click);

   private void button1_Click(object sender, EventArgs e)
{ }

这是Vs帮我们生成的按钮绑定事件,是不是和我们写的一样。但是细心的小朋友可能会说:参数定义不一样,Vs里面的事件都会有(object sender, EventArgs e)这两个参数。

其实这是微软定义的一种委托事件声明的规范。sender 传递触发者,EventArgs参数传递而外信息。比如我们写的那个demo sender就是热水器本身,参数我们就要传递的温度。下面我来修改一下。

首先添加一个参数类继承于EventArgs我们自定义的要传递的参数都继承于EventArgs。篇幅有限制,不详细介绍。可以自己查阅资料或者看我文章看透推荐的博客。

    public class BoiledEventArgs : EventArgs
{
public readonly int temperature;
public BoiledEventArgs(int temperature)
{
this.temperature = temperature;
}
}

修改了显示器类和报警器类的方法签名

    public class Monitor
{
public void ShowMessage(object sender, BoiledEventArgs e)
{
Console.WriteLine(string.Format("热水器在的温度已经{0}°啦,赶紧去洗澡吧", e.temperature));
}
}
public class Alarm
{
public void Police(object sender, BoiledEventArgs e)
{
Console.WriteLine(string.Format("热水器在的温度已经{0}°啦,赶紧去洗澡吧", e.temperature));
}
}

修改热水器类

    public delegate void Prompt(object sender, BoiledEventArgs e);
public class WaterHeater
{
private Prompt promt; //定义Prompt类型事件
public event Prompt OnPromptEvent;
public int temperature = ;
public void BoilWater()
{
for (int i = ; i < ; i++)
{
temperature++;
}
BoiledEventArgs e = new BoiledEventArgs(temperature);
OnPromptEvent(this, e);
}
}

main方法是不用动的。

完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace 委托和事件
{
public delegate void Prompt(object sender, BoiledEventArgs e);
public class WaterHeater
{
private Prompt promt; //定义Prompt类型事件
public event Prompt OnPromptEvent;
public int temperature = ;
public void BoilWater()
{
for (int i = ; i < ; i++)
{
temperature++;
}
BoiledEventArgs e = new BoiledEventArgs(temperature);
OnPromptEvent(this, e);
}
} // 定义BoiledEventArgs类,传递需要的的信息
public class BoiledEventArgs : EventArgs
{
public readonly int temperature;
public BoiledEventArgs(int temperature)
{
this.temperature = temperature;
}
} public class Monitor
{
public void ShowMessage(object sender, BoiledEventArgs e)
{
Console.WriteLine(string.Format("热水器在的温度已经{0}°啦,赶紧去洗澡吧", e.temperature));
}
}
public class Alarm
{
public void Police(object sender, BoiledEventArgs e)
{
Console.WriteLine(string.Format("热水器在的温度已经{0}°啦,赶紧去洗澡吧", e.temperature));
}
}
}

讲到了。我就介绍完啦。最后有一点仓促收尾。哈哈。想要学习的小伙伴可以看我文章推荐的两个博客啦。目前见过写的最好的了。我这个主要是自己纪录学习下。写下来理解更深刻,印象更胜。不适合大家学习。纯属个人笔记。

8.C#知识点:委托和事件的更多相关文章

  1. [ASP.NET MVC 大牛之路]02 - C#高级知识点概要(1) - 委托和事件

    在ASP.NET MVC 小牛之路系列中,前面用了一篇文章提了一下C#的一些知识点.照此,ASP.NET MVC 大牛之路系列也先给大家普及一下C#.NET中的高级知识点.每个知识点不太会过于详细,但 ...

  2. C#一些知识点:委托和事件的区别

    在C#中,委托和事件是比较容易混淆的两个知识点,本篇博客就记录一下委托和事件之间的区别. 定义上的区别 委托:委托实际上是一个类,用来表示一个函数,可以理解为C++中的函数指针. 事件:事件是一个修饰 ...

  3. [ASP.NET 大牛之路]02 - C#高级知识点概要(1) - 委托和事件

    在ASP.NET MVC 小牛之路系列中,前面用了一篇文章提了一下C#的一些知识点.照此,ASP.NET MVC 大牛之路系列也先给大家普及一下C#.NET中的高级知识点.每个知识点不太会过于详细,但 ...

  4. C# 委托 、事件、同步、异步知识点归纳

    一.委托 基本用法: 1.声明一个委托类型.委托就像是‘类'一样,声明了一种委托之后就可以创建多个具有此种特征的委托.(特征,指的是返回值.参数类型) public delegate void Som ...

  5. C#知识体系(二)用案例来理解委托与事件

    上一篇博客讲到了LinQ和lambda的常用方法 还有很多我们未知但c#设计团队已经为我们封装好的类和方法.随着我们不断的熟悉C#语言,渐渐的就会接触到其他的知识点,委托.事件.反射.线程.同步,异步 ...

  6. .Net之美读书系列(一):委托与事件

    开启新的读书之旅,这次读的书为<.Net之美:.Net关键技术深入解析>. 我是选择性阅读的,把一些自己觉得容易忘记的,或者比较重要的知识点记录下来,以便以后能方便呢查阅. 尊重书本原作者 ...

  7. C#基本功之委托和事件

    定义:委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用. 在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联 目的:方法声明和方法实现的分离,使得程序更容易扩展 一 ...

  8. C#编程语言之委托与事件(二)—— C#事件

    前面已经大致讲述了C#委托的一些基础知识点,本文接下来的内容是C#中的事件(Event),在此我提个建议,如果是刚接触C#的委托类型的朋友可以先看到这里,等熟悉了委托的使用之后(大约1-2天)再来了解 ...

  9. 《C#从现象到本质》读书笔记(六)第8章委托和事件

    <C#从现象到本质>读书笔记(六)第二部分 C#特性 第8章委托和事件 从这一部分开始,知识点就相对少了,重要的是代码练习.奈何太高深的代码平常不怎么用,这些特性也不是经常写代码的. 委托 ...

随机推荐

  1. android 获取 imei号码

    Imei = ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)) .getDeviceId(); 1.加入权限 在manifest.xml ...

  2. 通过 sysprocesses 简单查询死锁及解决死锁办法

    简单查询死锁,如下四步可以轻松解决: 第一步:查询死锁语句 1: 条件是 blocked <> 0 select dbid,* from sys.sysprocesseswhere 1=1 ...

  3. 【转】AngularJs HTTP请求响应拦截器

    任何时候,如果我们想要为请求添加全局功能,例如身份认证.错误处理等,在请求发送给服务器之前或服务器返回时对其进行拦截,是比较好的实现手段. angularJs通过拦截器提供了一个从全局层面进行处理的途 ...

  4. 564. Find the Closest Palindrome

    Given an integer n, find the closest integer (not including itself), which is a palindrome. The 'clo ...

  5. jzoj4229

    按照題意暴力模擬即可 #include<bits/stdc++.h> using namespace std; int m; typedef long long ll; ll a1,q,n ...

  6. python -猜字小游戏

    代码运行效果如下: 注意: 1.必须要在python3环境想使用 2.QQ:3084276329(一起交流学习) 3.还请大家评论 Guess the word game代码如下: #! /usr/b ...

  7. 上下文相关的GMM-HMM声学模型

    一.上下文对音素发音的语谱轨迹的影响 受到上下文的影响,同一个音素的发音语谱轨迹不同 为提高识别准确率,对音素建模时应将这种上下文影响考虑在内 二.基于上下文相关的音素建模 注意,非单音素建模中,每个 ...

  8. Liferay开发实战(1):入门

    网址: https://www.liferay.com/zh/ 文档: https://dev.liferay.com/develop 入门文章网上很多,中文的较少,存在版本太旧的问题,也缺少一步一步 ...

  9. python socket 编程简单入门

    想讲讲套接字的概念 套接字,即英文socket的中文意译,起源于20世纪70年代,是加利福利亚大学的伯克利版本UNIX(称为BSD UNIX)的一部分.目的是实现主机上运行的一个程序与另一个运行的程序 ...

  10. POJ 2782

    #include <iostream> #include <algorithm> #define MAXN 100005 using namespace std; int _m ...