• 【温故知新】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));
                }
            }
    
        }
    }
  • 相关阅读:
    Ubuntu 开发环境
    机器学习笔记-相似度
    ElasticSearch 笔记-分布式工作原理
    ElasticSearch 笔记-别名
    ElasticSearch 笔记-映射
    ElasticSearch 笔记-基本概念
    Linux 二 常用命令
    经典中的经典算法:动态规划(详细解释,从入门到实践,逐步讲解)
    图解Transformer
    CUDA9.0+tensorflow-gpu1.8.0+Python2.7服务器环境搭建经验
  • 原文地址:https://www.cnblogs.com/leestar54/p/4591959.html
Copyright © 2020-2023  润新知