• 理解事件(Event)


    Overview

    在前几章,我们已经对委托有了一个完整的了解了,本章将会对事件进行一下介绍:

    相对于委托,事件再是我们更加频繁的接触的,比如 鼠标的click 事件,键盘的 keydown 事件等等。

    事件的特点:

    • 只能进行 += 或者 -= 操作
    • 只能在,定义事件的类的内部调用事件,在其他类中不能调用

    大家还记不记得学面向对象的时候,对属性是怎么描述的

    对字段的封装,为了保护字段!

    那么,事件之于委托,也是同样的目的, 对委托的封装,为了保护委托

    我们在写代码的时候,一直会遵循这么一个规范: 永远不要经字段暴露出来! ,那么委托同样是这样能的,至于为什么这样,下文会有详细的介绍。

    Event的语法

    使用事件就要用到 event 关键字,并且事件是对委托的封装,有了委托才能有事件。

    1. 定义一个委托
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace UnderstandDelegate
    {
        public delegate void SimpleHandler();
    }
    
    1. 将委托封装为事件
    public event SimpleHandler SimpleEvent;
    

    为什么要引入事件

    为什么要引入属性的概念? 因为,将字段暴露出来不安全. 为什么引入事件,因为将委托暴露出来不安全。让我们来看一看为什么是这样。

    1. 定义一个委托
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace UnderstandDelegate
    {
        public delegate void SayHelloHandler();
    }
    
    
    1. 建立一个Person类
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace UnderstandDelegate
    {
        public class Person
        {
            public SayHelloHandler sayHelloHandler;
    
            public void SayHello()
            {
                if (sayHelloHandler != null)
                    sayHelloHandler.Invoke();
            }
        }
    }
    
    1. 调用Person类
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace UnderstandDelegate
    {
        class Program
        {
            static void Main(string[] args)
            {
                Person person = new Person();
                person.sayHelloHandler += ChinaStyleSayHello;
                person.sayHelloHandler += EnglishStyleSayHello;
            }
    
            static void ChinaStyleSayHello()
            {
                Console.WriteLine("你好");
            }
    
            static void EnglishStyleSayHello()
            {
                Console.WriteLine("Hello");
            }
    
            static void JapanStyleSayHello()
            {
                Console.WriteLine("坑你急哇");
            }
        }
    }
    
    

    上面的代码,没有问题,是的确实是这样,如果没有意外的话。 请注意,我将犯一些致命的错误:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace UnderstandDelegate
    {
        class Program
        {
            static void Main(string[] args)
            {
                Person person = new Person();
                person.sayHelloHandler += ChinaStyleSayHello;
                person.sayHelloHandler += EnglishStyleSayHello;
                //错误在这里,将之前赋值给委托的方法清空了
                person.sayHelloHandler = null;
                person.sayHelloHandler += JapanStyleSayHello;
            }
    
            static void ChinaStyleSayHello()
            {
                Console.WriteLine("你好");
            }
    
            static void EnglishStyleSayHello()
            {
                Console.WriteLine("Hello");
            }
    
            static void JapanStyleSayHello()
            {
                Console.WriteLine("坑你急哇");
            }
        }
    }
    
    

    这还得了,如果说,因为你的一时疏忽,出现了上面的操作,如果说这个情况,是在一个大型的程序中,这种情况可是很致命的!

    还有这种情况

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace UnderstandDelegate
    {
        class Program
        {
            static void Main(string[] args)
            {
                Person person = new Person();
                person.sayHelloHandler += ChinaStyleSayHello;
                person.sayHelloHandler += EnglishStyleSayHello;
                //错误在这里,将之前赋值给委托的方法清空了
                person.sayHelloHandler = null;
                person.sayHelloHandler += JapanStyleSayHello;
                //在Person类的外部,调用的Person类内部的委托
                person.sayHelloHandler();
            }
    
            static void ChinaStyleSayHello()
            {
                Console.WriteLine("你好");
            }
    
            static void EnglishStyleSayHello()
            {
                Console.WriteLine("Hello");
            }
    
            static void JapanStyleSayHello()
            {
                Console.WriteLine("坑你急哇");
            }
        }
    }
    
    

    这用情况,就更致命了,想象这么一个场景: 如果我们做了一个金融方面的项目,这项目中涉及到了资金的流转等敏感操作,恰恰这个操作,是交给一个委托来执行的,如果我们出现了这么一个情况,在不在调用的时候,自己手动调用了委托,那么,请做好老板找你谈话的准备吧。

    这些问题都可以用事件来解决

    我们需要对Person类,进行一下简单的修改。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace UnderstandDelegate
    {
        public class Person
        {
            //将委托封装为了事件
            public event SayHelloHandler sayHelloHandler;
    
            public void SayHello()
            {
                if (sayHelloHandler != null)
                    sayHelloHandler.Invoke();
            }
        }
    }
    

    我们在看一下原来的代码

    根本就不会被编译,那么这样就从根源上解决了我们使用委托,可能出现的高风险的问题。因为他根本就不让你编译,必须修改了才行![img](file:///C:UsersITAppDataLocalTempSGPicFaceTpBq19984B10103B6.png)。

    结语

    可能,刚刚接触委托和事件的时候,刚刚回被这两个的概念搞得一脸懵逼,只需要记住: 事件是对委托的封装 即可。最后,希望本文可以帮助到各位看官。

    文中有任何纰漏之处还望指出,以免笔者,误人误己,在此拜谢。

  • 相关阅读:
    CentOS下MySQL忘记root密码解决方法【转载】
    Linux给用户添加sudo权限
    C++11 std::chrono库详解
    npm install Error:EPROTO: protocol error, symlink '../mime/cli.js' -> '/vagrant/src/nodejs/node_modules/express/node_modules/send/node_modules/.bin/mime'
    DOT + graphviz 轻松画图
    关于阿里云ESC上go语言项目编译6l: running gcc failed: Cannot allocate memory
    Ubunu下安装Docker
    Ubunu下安装mongoDB
    Docker私有仓库Registry的搭建验证
    Linux的SOCKET编程详解
  • 原文地址:https://www.cnblogs.com/slyfox/p/7517429.html
Copyright © 2020-2023  润新知