【温故知新】c#事件event

从上一篇文章【温故知新】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  3
  .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.0
  IL_0001:  ldfld      class Delegate.Teacher/NotifyDelegate Delegate.Teacher::FindStudentLove
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.1
  IL_0009:  ldloc.1
  IL_000a:  ldarg.1
  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.2
  IL_0016:  ldarg.0
  IL_0017:  ldflda     class Delegate.Teacher/NotifyDelegate Delegate.Teacher::FindStudentLove
  IL_001c:  ldloc.2
  IL_001d:  ldloc.1
  IL_001e:  call       !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<class Delegate.Teacher/NotifyDelegate>(!!0&,
                                                                                                                          !!0,
                                                                                                                          !!0)
  IL_0023:  stloc.0
  IL_0024:  ldloc.0
  IL_0025:  ldloc.1
  IL_0026:  ceq
  IL_0028:  ldc.i4.0
  IL_0029:  ceq
  IL_002b:  stloc.3
  IL_002c:  ldloc.3
  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  3
  .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.0
  IL_0001:  ldfld      class Delegate.Teacher/NotifyDelegate Delegate.Teacher::FindStudentLove
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.1
  IL_0009:  ldloc.1
  IL_000a:  ldarg.1
  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.2
  IL_0016:  ldarg.0
  IL_0017:  ldflda     class Delegate.Teacher/NotifyDelegate Delegate.Teacher::FindStudentLove
  IL_001c:  ldloc.2
  IL_001d:  ldloc.1
  IL_001e:  call       !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<class Delegate.Teacher/NotifyDelegate>(!!0&,
                                                                                                                          !!0,
                                                                                                                          !!0)
  IL_0023:  stloc.0
  IL_0024:  ldloc.0
  IL_0025:  ldloc.1
  IL_0026:  ceq
  IL_0028:  ldc.i4.0
  IL_0029:  ceq
  IL_002b:  stloc.3
  IL_002c:  ldloc.3
  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));
            }
        }

    }
}
时间: 2024-10-06 01:09:49

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

μCOS-II系统之事件(event)的使用规则及Semaphore实例

*************************************************************************************************************************** 作者:EasyWave                                                时间:2014.05.31 类别:μC/OS-II-操作系统                                  声明:

μCOS-II系统之事件(event)的使用规则及Semaphore的互斥量用法

*************************************************************************************************************************** 作者:EasyWave                                                时间:2014.05.31 类别:μC/OS-II-操作系统                                  声明:

μCOS-II系统之事件(event)的使用规则及MUTEX实例

*************************************************************************************************************************** 作者:EasyWave                                                时间:2014.05.31 类别:μC/OS-II-操作系统                                  声明:

学习笔记---Javascript事件Event、IE浏览器下的拖拽效果

学习笔记---Javascript事件Event.IE浏览器下的拖拽效果     1. 关于event常用属性有returnValue(是否允许事件处理继续进行, false为停止继续操作).srcElement(触发事件的事件源对象)和attachEvent("onclick",function(){...}); 2. a. 实现拖放(Drag and Drop): 目前支支持IE, 若定制某对象为可拖放对象, 则必须覆盖目标对象的dragenter和dragover事件, 可以用e

[数据库] Navicat for MySQL事件Event实现数据每日定期操作

在我们操作数据库过程中,通常会遇到一些某个时间点操作数据库的问题,例如:        (1).每天凌晨12点对数据库进行定时备份,结算和汇总:        (2).每天凌晨2点删除数据库前三天的数据:        (3).插入某个数据超过一定时间改变某个值的状态,比如预警系统.        这里就需要通过Event事件进行简单操作,下面将详细处理.你可能会想到通过触发器实现,但是如果是同一张表Insert插入数据后,但是触发器再进行Update更新操作是不行的,所以需要尝试通过Event

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

1.delegate是什么 某种意义上来讲,你可以把delegate理解成C语言中的函数指针,它允许你传递一个类A的方法m给另一个类B的对象,使得类B的对象能够调用这个方法m,说白了就是可以把方法当作参数传递. 不过delegate和函数指针还是有点区别的,delegate有许多函数指针不具备的优点. 首先,函数指针只能指向静态函数,而delegate既可以引用静态函数,又可以引用非静态成员函数.在引 用非静态成员函数时,delegate不但保存了对此函数入口指针的引用,而且还保存了调用此函数的

C#:代表(delegate)和事件(event) (转)

代表(delegate): 它是C#语言里面的函数指针,代表可以指向某一个函数,在运行的时候调用这个函数的实现.下面来看看它的实现步骤: 声明一个delegate对象. 实现和delegate具有相同参数和返回值的函数实现(可以是静态和非静态的). 产生一个delegate对象的时候,把你刚刚实现的函数作为参数传给他的构造函数. 请看下面例子: using System;using System.Collections.Generic;using System.Text; namespace U

C#事件(event)解析

事件(event),这个词儿对于初学者来说,往往总是显得有些神秘,不易弄懂.而这些东西却往往又是编程中常用且非常重要的东西.大家都知道windows消息处理机制的重要,其实C#事件就是基于windows消息处理机制的,只是封装的更好,让开发者无须知道底层的消息处理机制,就可以开发出强大的基于事件的应用程序来. 先来看看事件编程有哪些好处. 在以往我们编写这类程序中,往往采用等待机制,为了等待某件事情的发生,需要不断地检测某些判断变量,而引入事件编程后,大大简化了这种过程: - 使用事件,可以很方

事件Event对象

事件event对象 当事件发生时,会向调用函数传递一个event对象,event对象记录当前事件发生时的环境信息. 一个事件只能对应一个event对象,并且event对象是短暂存在的. DOM中的event对象的使用方法 1.在HTML标记中,通过事件来调用函数,向函数传递一个event参数,该参数就是一个event对象,这个event必须全小写.注意:这个event参数是固定的 <img id="img01" src="images/01.jpg" oncl