从上一篇文章【温故知新】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. asp.net中实现群发邮件功能

    前段时间在帮老师开发的网站中需要用到一个群发邮件的功能,而自己之前学习cms系统的时候用的we7的群发邮件功能也有一些问题,于是乎便自己去网上查了一下资料,自己总结了一下,并且封装成了一个类,亲测有用 ...

  2. sublime text3使用心得及个人配置 sublime常用快捷键大全

    下载好后:1.安装package controlimport urllib.request,os; pf = 'Package Control.sublime-package'; ipp = subl ...

  3. ios 编码转换 保存文件

    - (NSString *)SaveFileToDocuments:(NSString *)url { // NSString *url = @"http://172.28.250.70/a ...

  4. in_array函数的第三个参数 strict

    看段代码 <?php $array = array('testing',0,'name'); var_dump($array); var_dump(in_array('foo', $array) ...

  5. poj 3254

    状态压缩 dp dp[i][j] 为第 i 行状态为 j 的总数 #include <cstdio> #include <cstdlib> #include <cmath ...

  6. CRF++中文分词使用指南

    http://blog.csdn.net/marising/article/details/5769653 前段时间写了中文分词的一些记录里面提到了CRF的分词方法,近段时间又研究了一下,特把方法写下 ...

  7. GCD初步认识

    //(1)用异步函数往并发队列中添加任务, //总结:同时开启三个子线程 - (void)test1 { //1.获得全局的并发队列 dispatch_queue_t queue = dispatch ...

  8. iOS 隐藏顶部状态栏方式和更改颜色

    plist文件里面添加 AppDelegate: //显示状态栏 [[UIApplication sharedApplication]setStatusBarHidden:NO]; //将状态栏颜色设 ...

  9. Android屏幕适应详解(一)

    一.关于布局适配 1.不要使用绝对布局 2.尽量使用match_parent 而不是fill_parent . 3.能够使用权重的地方尽量使用权重(android:layout_weight) 4.如 ...

  10. 使用Subversion进行版本控制

    使用Subversion进行版本控制 针对 Subversion 1.4(根据r2866编译) Ben Collins-Sussman Brian W. Fitzpatrick C. Michael  ...