首页 > 其他分享 >由浅入深理解委托与事件

由浅入深理解委托与事件

时间:2022-12-08 00:11:54浏览次数:64  
标签:由浅入深 委托 void SayHelloWay 理解 static 方法 public

引言

  看过上一篇文章的朋友应该知道,要想给一个类添加自定义事件,首先要添加一个委托,然后通过这个委托声明一个事件,在主程序中其他类只要有符合那个委托的方法,就可以用这个方法订阅那个自定义事件,当自定义事件发布时,就会调用委托的方法,这其中的指导思想就是发布-订阅模型。可是,大家有没有觉得,当我们在自定义类中调用事件后,它居然就能自动调用订阅这个事件的所有方法,这个过程很神奇。今天,我们就来尝试着揭开这层神秘的面纱。

委托

  首先,什么是委托,委托在我的个人理解中相当于C中的函数指针,但它跟函数指针在使用方式上还是有些不太一样。用微软官方的话讲,在 .NET 中委托提供后期绑定机制,后期绑定意味着调用方在你所创建的算法中至少提供一个方法来实现算法的一部分(摘自微软教程)。我建议微软教程大家随意瞄一眼就好,从我的角度看就不像在说人话,我们还是来看看民间对于委托的介绍。


 

  什么是委托?   首先要知道什么是委托,用最通俗易懂的话来讲,你就可以把委托看成是用来执行方法(函数)的一个东西。   如何使用委托?   在使用委托的时候,你可以像对待一个类一样对待它。即先声明,再实例化。只是有点不同,类在实例化之后叫对象或实例,但委托在实例化后仍叫委托。

  委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。我们知道委托是一个引用类型,所以它具有引用类型所具有的通性。它保存的不是实际值,而是保存对存储在托管堆(managed heap)中的对象的引用。那它保存的是对什么的引用呢?委托保存的是对函数(function)的引用(从水平线开始均摘自百度百科)。我认为百度百科解释的非常好,包括它后面写的对于学习过C/C++的人来说与C中的函数指针的区别,不过我没放上来因为有点长,有兴趣的大家可以跳转链接看。

代码释义

  可能看完定义,大家还是不太懂,那么我将结合代码再讲一次,当然熟悉委托的朋友可以跳过这一小节。

  我们可以把委托的写法和使用与类的写法和使用联系起来,这样更方便自己理解。可以先看下这段简单代码:

  public class Program
    {
        //写一个委托,可以理解为就是定义了一个方法类型的模板,这个模板名就叫做SayHelloWay(可以类比写一个类,然后类就是生成一堆数据和方法的模板)
        public delegate void SayHelloWay();

        public static void SayHelloByConsole()
        {
            Console.WriteLine("Hello");
        }

        public static void SayHelloByDiagnostics()
        {
            System.Diagnostics.Debug.WriteLine("Hello");
        }

        static void Main(string[] args)
        {
            //可以像创建一个类的实例一样,创建一个委托,但这个委托的构造函数需要一个方法参数
            SayHelloWay sayHello = new SayHelloWay(SayHelloByConsole);
            //在委托后面添加()即可调用在构造函数构造时传入的方法即SayHelloByConsole,可以理解这个方法就是委托的方法
            sayHello(); //可以像调用方法一样使用委托,即括号里可以传入参数(前提方法声明时本来参数列表就有参数)
            sayHello = new SayHelloWay(SayHelloByDiagnostics);
            sayHello();
        }
    }

//控制台结果:Hello
//VS输出面板结果:Hello

既然委托是定义某一种方法的模板,那么我们完全可以拿这个模板作为某个方法的参数类型,这样就可以往这个方法里传入方法,于是回调函数就来了。

    public class Program
    {
        public delegate void SayHelloWay();

        public static void SayHelloByConsole()
        {
            Console.WriteLine("Hello");
        }

        public static void SayHelloByDiagnostics()
        {
            System.Diagnostics.Debug.WriteLine("Hello");
        }

        public static void SayHello(SayHelloWay say)
        {
            say();
        }

        static void Main(string[] args)
        {
            SayHello(SayHelloByConsole);
        }

其实创建委托实例的方式不止new这一种,以下我再演示下创建委托实例的另外两种方式,分别是直接赋值和lambda表达式

        static void Main(string[] args)
        {
            //直接赋值
            SayHelloWay sayhello = SayHelloByDiagnostics;
            sayhello();
            //lambda表达式赋值,也叫匿名委托
            SayHelloWay sayhello1 = () =>
            {
                Console.Write("hello by lambda");
            };
            sayhello1();
        }

委托可以被订阅多个方法,也就是说,一个委托身上可以有多个方法,调用委托时,会触发它身上绑定的所有方法。只需要给委托“+=”或者“+”新的方法名即可,这种绑定多个方法的委托就叫做多播委托,如下代码所示:

        static void Main(string[] args)
        {
            SayHelloWay sayHello = SayHelloByConsole;
           // sayHello = sayHello + SayHelloByDiagnostics;  这种不常用
            sayHello += SayHelloByDiagnostics;  //这种常用些
            sayHello();
        }

如果想在多播委托中去除一个方法,可以使用“-”或者“-=”,这里不做演示,因其用法与“+=”或者“+”相同。

 事件

 

标签:由浅入深,委托,void,SayHelloWay,理解,static,方法,public
From: https://www.cnblogs.com/hlz2516/p/16934255.html

相关文章

  • 多模态文档LayoutLM版面智能理解技术演进-纪传俊
    多模态算法兴起的背景办公文档是各行各业最基础也是最重要的信息载体,不管是金融、政务、制造业、零售行业等等,各种类型的文档都是业务流转过程中必不可少的数字资料。以银行......
  • 多模态文档LayoutLM版面智能理解技术演进-纪传俊
    多模态算法兴起的背景办公文档是各行各业最基础也是最重要的信息载体,不管是金融、政务、制造业、零售行业等等,各种类型的文档都是业务流转过程中必不可少的数字资料。以银行......
  • mysql page_一文理解MySQL中的page页--转
    在介绍InnoDB中的页的时候,很有必要先让大家了解一下InnoDB中的存储结构从InnoDB存储引擎的逻辑结构看,所有数据都被逻辑地存放在一个空间内,称为表空间(tablespace),而表空......
  • 谈谈对keep-alive的理解
    1.是什么:vue系统自带的一个组件,用来缓存组件,可以提高性能。2.应用场景:一些重复的页面,只需要请求一次接口或者可能会重复请求一个接口的页面。3.生命周期:第一次进入执行vu......
  • 来啦!滤波SLAM之MSCKF原理解析与源码详解
    以下内容来自从零开始机器人SLAM知识星球每日更新内容点击领取学习资料→机器人SLAM学习资料大礼包MSCKF全称Multi-StateConstraintKalmanFilter(多状态约束卡尔曼......
  • 理解Nodejs中的进程间通信
    前置知识文件描述符在Linux系统中,一切都看成文件,当进程打开现有文件时,会返回一个文件描述符。文件描述符是操作系统为了管理已经被进程打开的文件所创建的索引,用来指......
  • 理解NodeJS多进程
    序言一次面试中,我提到自己用过pm2,面试接着问:「那你知道pm2父子进程通信方式吗」。我大概听说pm2有cluster模式,但不清楚父子进程如何通信。面试结束后把NodeJS的多进程重新......
  • Go常见面试题【由浅入深】2022版
    Go语言相比C++/Java等语言是优雅且简洁的,是笔者最喜爱的编程语言之一,它既保留了C++的高性能,又可以像Java,Python优雅的调用三方库和管理项目,同时还有接口,自动垃圾回收和goro......
  • 对于噪声数据理解以及Min-Max 规范化和 Score规范化(零-均值规范化)的实例【数据预处
    一.噪声数据噪声数据(NoisyData)就是无意义的数据,这个词通常作为损坏数据的同义词使用。1.分箱:通过考察数据的“近邻”(周围的值)来光滑有序数据的值。局部光滑2.回归:......
  • SLAM十四讲——关于李群与李代数的理解
    1、李代数的存在是为了更好地估计变换矩阵T。2、李群对乘法封闭。3、李代数是对加法封闭(因为其由向量组成)。4、李代数对应李群的正切空间,它描述了李群局部的导数。5、对于某......