从上一篇文章【温故知新】C#委托delegate可知,委托delegate和事件Event非常的相似,区别就是event关键字,给delegate穿上了个“马甲”。

让我们来看官方定义:

类或对象可以通过事件向其他类或对象通知发生的相关事情。 发送(或引发)事件的类称为“发行者”,接收(或处理)事件的类称为“订户”。

event 关键字用于在发行者类中声明事件。

定义非常明确,通过事件向其他类或对象通知发生的相关事情,用来实现的观察者模式。

还是通过之前的代码例子,看看声明delegate和event

        //声明一个委托类型,通知家长
public delegate void NotifyDelegate(string msg); //老师被吩咐了1个委托
//声明委托:在发现早恋时时通知家长
private NotifyDelegate NotifyStudentLove; //声明事件,如果发现学生早恋! 就要通知那些订阅了这个事件的家长。
public event NotifyDelegate FindStudentLove;

让我们通过IL DASM来看看编译之后事件event的真正面目~

.event Delegate.Teacher/NotifyDelegate FindStudentLove
{
.addon instance void Delegate.Teacher::add_FindStudentLove(class Delegate.Teacher/NotifyDelegate)
.removeon instance void Delegate.Teacher::remove_FindStudentLove(class Delegate.Teacher/NotifyDelegate)
} // end of event Teacher::FindStudentLove
.method public hidebysig specialname instance void
add_FindStudentLove(class Delegate.Teacher/NotifyDelegate 'value') cil managed
{
// 代码大小 48 (0x30)
.maxstack
.locals init (class Delegate.Teacher/NotifyDelegate V_0,
class Delegate.Teacher/NotifyDelegate V_1,
class Delegate.Teacher/NotifyDelegate V_2,
bool V_3)
IL_0000: ldarg.
IL_0001: ldfld class Delegate.Teacher/NotifyDelegate Delegate.Teacher::FindStudentLove
IL_0006: stloc.
IL_0007: ldloc.
IL_0008: stloc.
IL_0009: ldloc.
IL_000a: ldarg.
IL_000b: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_0010: castclass Delegate.Teacher/NotifyDelegate
IL_0015: stloc.
IL_0016: ldarg.
IL_0017: ldflda class Delegate.Teacher/NotifyDelegate Delegate.Teacher::FindStudentLove
IL_001c: ldloc.
IL_001d: ldloc.
IL_001e: call !! [mscorlib]System.Threading.Interlocked::CompareExchange<class Delegate.Teacher/NotifyDelegate>(!!&,
!!,
!!)
IL_0023: stloc.
IL_0024: ldloc.
IL_0025: ldloc.
IL_0026: ceq
IL_0028: ldc.i4.
IL_0029: ceq
IL_002b: stloc.
IL_002c: ldloc.
IL_002d: brtrue.s IL_0007
IL_002f: ret
} // end of method Teacher::add_FindStudentLove
.method public hidebysig specialname instance void
remove_FindStudentLove(class Delegate.Teacher/NotifyDelegate 'value') cil managed
{
// 代码大小 48 (0x30)
.maxstack
.locals init (class Delegate.Teacher/NotifyDelegate V_0,
class Delegate.Teacher/NotifyDelegate V_1,
class Delegate.Teacher/NotifyDelegate V_2,
bool V_3)
IL_0000: ldarg.
IL_0001: ldfld class Delegate.Teacher/NotifyDelegate Delegate.Teacher::FindStudentLove
IL_0006: stloc.
IL_0007: ldloc.
IL_0008: stloc.
IL_0009: ldloc.
IL_000a: ldarg.
IL_000b: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_0010: castclass Delegate.Teacher/NotifyDelegate
IL_0015: stloc.
IL_0016: ldarg.
IL_0017: ldflda class Delegate.Teacher/NotifyDelegate Delegate.Teacher::FindStudentLove
IL_001c: ldloc.
IL_001d: ldloc.
IL_001e: call !! [mscorlib]System.Threading.Interlocked::CompareExchange<class Delegate.Teacher/NotifyDelegate>(!!&,
!!,
!!)
IL_0023: stloc.
IL_0024: ldloc.
IL_0025: ldloc.
IL_0026: ceq
IL_0028: ldc.i4.
IL_0029: ceq
IL_002b: stloc.
IL_002c: ldloc.
IL_002d: brtrue.s IL_0007
IL_002f: ret
} // end of method Teacher::remove_FindStudentLove

实际上编译器会帮你生成如下类似代码:

// 1. A PRIVATE delegate field that is initialized to null
private EventHandler<NewMailEventArgs> NewMail = null;
// 2. A PUBLIC add_Xxx method (where xxx is the Event name)
// Allows objects to register interest in the event.
[MethodImpl(MethodImplOptions.Synchronized)]
public void add_NewMail(EventHandler<NewMailEventArgs> value) {
  NewMail = (EventHandler<NewMailEventArgs>)
  Delegate.Combine(NewMail, value);
}
// 3. A PUBLIC remove_Xxx method (where Xxx is the Event name)
// Allows objects to unregister interest in the event.
[MethodImpl(MethodImplOptions.Synchronized)]
public void remove_NewMail(EventHandler<NewMailEventArgs> value) {
  NewMail = (EventHandler<NewMailEventArgs>)
  Delegate.Remove(NewMail, value);
}

当一个声明delegate前添加event之后,编译器为我们封装了delegate,这样,在之后的调用,就开放了+=,-=两个方法,这样极大保证了对象安全。

我们在使用c#内置事件的时候,总会发现EventHandler,EventArgs。这是因为.NET Framework为了规范,方便开发,已经为事件发布了准则。

.NET Framework 类库中的所有事件均基于 EventHandler 委托,定义如下:

public delegate void EventHandler(object sender, EventArgs e);

让我们把上一篇的代码改为符合.NET Framework事件准则

主场景:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace Delegate
{
class Program
{
static void Main(string[] args)
{
//家长A,B
Parent pa = new Parent();
Parent pb = new Parent(); //家长A,B分别委托老师发现早恋情况时通知他们
Teacher teacher = new Teacher();
teacher.FindStudentLove += pa.ReceiveMsg;
teacher.FindStudentLove += pb.ReceiveMsg; //老师开始检查早恋情况
teacher.CheckLove(); }
}
}

家长类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Delegate
{
public class Parent
{
/// <summary>
/// 接收消息
/// </summary>
/// <param name="msg">通知消息</param>
public void ReceiveMsg(object sender, StudentLoveEventArgs arg)
{
Console.WriteLine("家长收到通知:" + arg.Message);
}
}
}

老师类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Delegate
{
public class StudentLoveEventArgs : EventArgs
{
public StudentLoveEventArgs(string s)
{
message = s;
}
private string message; public string Message
{
get { return message; }
set { message = value; }
}
} public class Teacher
{ //声明一个委托类型,通知家长
public delegate void NotifyDelegate(string msg); //老师被吩咐了1个委托
//声明委托:在发现早恋时时通知家长
private NotifyDelegate NotifyStudentLove; //声明事件,如果发现学生早恋! 就要通知那些订阅了这个事件的家长。
public event EventHandler<StudentLoveEventArgs> FindStudentLove; //如果还想委托老师发现学生玩手机的时候通知一声,再声明一个委托即可
private NotifyDelegate NotifyStudentPlayMobile; //封装委托,使其符合面向对象,event关键字就为我们自动封装了。
public void add_NotifyStudentLove(NotifyDelegate newdelegate)
{
NotifyStudentLove += newdelegate;
} public void CheckLove()
{
//某一天AB同学突然发生纠纷!被老师发现啦!
string msg = "A同学和B同学早恋啦!!";
//检查是否有人委托老师办事
if (FindStudentLove != null)
{
//果断通知家长
FindStudentLove(this, new StudentLoveEventArgs(msg));
}
} }
}

【温故知新】c#事件event的更多相关文章

  1. 事件EVENT与waitforsingleobject的使用

    事件event与waitforsingleobject的配合使用,能够解决很多同步问题,也可以在数据达到某个状态时启动另一个线程的执行,如报警. event的几个函数: 1.CreateEvent和O ...

  2. 经典线程同步 事件Event

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇 一个经典的多线程同步问题> <秒杀多线程第五篇 经典线程同步关键段CS> 上一篇中使用关键段来解决经典的多线程同步互斥问题 ...

  3. C#事件(event)解析

    事件(event),这个词儿对于初学者来说,往往总是显得有些神秘,不易弄懂.而这些东西却往往又是编程中常用且非常重要的东西.大家都知道windows消息处理机制的重要,其实C#事件就是基于window ...

  4. 事件[event]_C#

    事件(event): 1.       事件是类在发生其关注的事情时用来提供通知的方式.例如,封装用户界面控件的类可以定义一个在单击该控件时发生的事件.控件类不关心单击按钮时发生了什么,但它需要告知派 ...

  5. C#中的委托(Delegate)和事件(Event)

    原文地址:C#中的委托(Delegate)和事件(Event) 作者:jiyuan51 把C#中的委托(Delegate)和事件(Event)放到现在讲是有目的的:给下次写的设计模式--观察者(Obs ...

  6. MFC线程(三):线程同步事件(event)与互斥(mutex)

    前面讲了临界区可以用来达到线程同步.而事件(event)与互斥(mutex)也同样可以做到. Win32 API中的线程事件 HANDLE hEvent = NULL; void MainTestFu ...

  7. 重温委托(delegate)和事件(event)

    1.delegate是什么 某种意义上来讲,你可以把delegate理解成C语言中的函数指针,它允许你传递一个类A的方法m给另一个类B的对象,使得类B的对象能够调用这个方法m,说白了就是可以把方法当作 ...

  8. C#总结(二)事件Event 介绍总结

    最近在总结一些基础的东西,主要是学起来很难懂,但是在日常又有可能会经常用到的东西.前面介绍了 C# 的 AutoResetEvent的使用介绍, 这次介绍事件(event). 事件(event),对于 ...

  9. 多线程面试题系列(6):经典线程同步 事件Event

    上一篇中使用关键段来解决经典的多线程同步互斥问题,由于关键段的"线程所有权"特性所以关键段只能用于线程的互斥而不能用于同步.本篇介绍用事件Event来尝试解决这个线程同步问题.首先 ...

随机推荐

  1. 4-Highcharts 3D图之3D普通饼图

    <!DOCTYPE> <html lang='en'> <head> <title>4-Highcharts 3D图之3D普通饼图</title& ...

  2. 负MARGIN之讲解

    css中的负边距(negative margin)是布局中的一个常用技巧,只要运用得合理常常会有意想不到的效果.很多特殊的css布局方法都依赖于负边距,所以掌握它的用法对于前端的同学来说,那是必须的. ...

  3. 几个Google中国的访问IP

    前面几个IP的访问速度比较快. 74.125.31.106 173.194.45.20 173.194.45.19 173.194.45.18 173.194.45.17 173.194.45.16 ...

  4. Confluence Wiki Markup & Markdown

    Markup : 默认有支持 Markdown : 需先安装插件,插件下载地址: Confluence markdown : https://marketplace.atlassian.com/plu ...

  5. 三维云模拟Three.js

    http://www.mrdoob.com/#/131/clouds http://www.webgl.com/2012/03/webgl-demo-clouds/ <!DOCTYPE html ...

  6. HDU 1393 Weird Clock (英语,纪念题)

    这题简单,只要看懂题目就好,坑爹的是我的英语水平太差了,wa了n次,所以 仅此纪念 一下. //坑爹的英语题目,注意重点:move d times clockwise the current time ...

  7. PHP SESSION 保存到数据库

    PHP SESSION 的工作原理 在客户端(如浏览器)登录网站时,被访问的 PHP 页面可以使用 session_start() 打开 SESSION,这样就会产生客户端的唯一标识 SESSION ...

  8. Java集合框架(四)

    Collections    集合框架的工具类    着重讲解以下方法: 1.sort(): 1º根据元素的自然顺序对指定列表按升序进行排序,列表中的所有元素都必须实现comparable接口. pu ...

  9. JVM垃圾回收机制总结(7) :调优方法

    JVM调优工具 Jconsole,jProfile,VisualVM Jconsole : jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用.对垃圾回收算法有很详细的跟踪.详细说明参考这里 ...

  10. iOS:CALayer核心动画层上绘图

    在CALayer上绘图: •要在CALayer上绘图,有两种方法: 1.创建一个CALayer的子类,然后覆盖drawInContext:方法,可以使用Quartz2D API在其中进行绘图 2.设置 ...