我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C#中委托的基础介绍与实现方法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C#中委托的基础介绍与实现方法

这篇文章主要讲解了“C#中委托的基础介绍与实现方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C#中委托的基础介绍与实现方法”吧!

目录
  • 前言

  • 关于委托

  • 委托的实现

    • 一、基本实现方式

    • 二、使用委托时的一些特殊方式

      • 委托实例对象的创建多元化:

      • 事件绑定的多种方式

    • 三、委托的几种特殊实现方式

      • 1,使用Action方法

        • 2,使用Func方法

      • 四、委托的一些特殊小知识

        • 委托闭包的产生

        • 2,关于事件

    前言

    似乎委托对于C#而言是一种高级属性,但是我依旧希望你就算第一次看我的文章,也能有很大的收获。

    所以本博客的语言描述尽量简单易懂,知识点也是面向初入门对于委托不了解的学习者的。当然如果有幸有大佬发现文章的错误点,也欢迎留言指出!

    关于委托

    关于委托的介绍主要来源于C#文档:委托概述(本文章优势在于去掉一些不必要的细节,对于初学者而言简单高效)

    委托的定义主要是下面几个方面:

    • 委托是一种引用类型:表示对具有特定参数列表和返回类型的方法的引用

    • 在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联。 你可以通过委托实例调用方法

    委托本质上来讲就是将方法作为参数传递给其他方法的一种实现方式,当然开发者也可以直接去调用方法。但是当一个项目扩展到足够大时,这种直接调用的方式就会很复杂,难以维护。而委托不会,可以很方便的进行后期的扩展开发。只需要将自己的方法传入已经写好的对应的委托即可。而不需要再在大量的代码中找到调用处写入自己的方法。

    关于委托的一些特点是(暂时不了解没有关系):

    • 委托类似于 C++ 函数指针,但委托完全面向对象,不像 C++ 指针会记住函数,委托会同时封装对象实例和方法。

    • 委托允许将方法作为参数进行传递。

    • 委托可用于定义回调方法。

    • 委托可以链接在一起;例如,可以对一个事件调用多个方法。

    • 方法不必与委托类型完全匹配。 有关详细信息,请参阅使用委托中的变体。

    • 使用Lambda 表达式可以更简练地编写内联代码块。 Lambda表达式(在某些上下文中)可编译为委托类型。 若要详细了解lambda 表达式,请参阅 lambda 表达式。

    如果对于一个初学者,你可以简单的理解,委托就是一个更高级的调用方法的方式,而你要学习的,就是这种方式的实现方法,然后后期再慢慢理解更多的细节。

    委托的实现

    一、基本实现方式

    前面也说,委托是一个引用类型,要使用委托,肯定就需要对其进行定义并创建一个委托对象,下面使用一个带有一个参数的案例来理解委托

    public class DemoDelegate{    //T1:        delegate void TestDel(string s);        TestDel Del;        //T4:        static void Main(string[] args)        {            DemoDelegate demo = new DemoDelegate();            demo.CreateDelObject();            demo.Del?.Invoke("你们好");        }    //T3:        public void CreateDelObject()        {            Del += TestEventOne;            Del += TestEventTwo;        }    //T2:        public void TestEventOne(string str)        {            Console.WriteLine(str);        }        public void TestEventTwo(string str)        {            Console.WriteLine(str);        }        }

    如果你是刚刚接触委托这个概念,可能对于这些代码的含义不是特别了解,没关系,你可以根据注释的顺序来看代码并理解委托的实现机制:

    • T1:通过delegate关键字定义一个委托类型TestDel,并创建一个实例Del

    • T2: 也很好理解,创建两个测试方法,可以执行输出

    • T3: 是委托的关键,为刚刚创建的委托来添加事件方法

    • T4: 执行委托实例Del,可以简单理解为执行该实例绑定的所有事件方法

    当然有一些语法是比较独特的,比如说+=这样的语法,就是一种为委托添加事件方法的方法,而对于执行委托语句demo.Del?.Invoke("你们好");中Invoke()为执行该委托对象内方法的API,?则可以在Del委托对象为空时,系统不报错

    关于?的具体含义,可查阅:

    可为空引用类型

    其实委托主要是有这简单的四步来实现了,通过这个案例,更加明显的体现出委托将一系列方法作为参数来让其他方法去调用的特点。

    二、使用委托时的一些特殊方式

    通过上面的案例,可以看出对于委托的实现是很简单的,但是C#还是为我们提供了很多更加间接或者集成的用法,具体有:

    1、委托实例对象的创建多元化:

    创建委托类型的多种方式:

    • 直接使用New来创建一个对象,但是注意,在New时需要绑定直接添加一个事件方法,不然会报错(这也是与其他引用类型不同的地方)

    • 使用直接赋值的方式创建

    • 定义方法名,后期添加事件方法时自动实例(上面的例子)

    关于具体的实现代码:

    public class DemoDelegate{    delegate void TestDel(string str);    //第一种:New 的同时绑定方法    TestDel DelOne = new TestDel(TestEventOne);    //第二种    TestDel DelTwo = TestEventOne;        static void TestEventOne(string str)    {        Console.WriteLine(str);    }}

    注意,关于第三种后期绑定有一种现象值得留意,在使用后期绑定时,如果你是创建一个成员变量(全局变量)委托类型,后期绑定可以直接使用+=来增加委托绑定的方法,而你如果是创建一个局部变量的委托,需要先通过=来添加一个方法后,才能使用+=来增加方法,不然就会报空,如图:

    C#中委托的基础介绍与实现方法

    出现这种情况的原因在于成员变量与局部变量之间的区别,如果想要了解更多,可以执行百度,这边列出两者在本案例中的区别:

    成员变量:有默认初始化值局部变量:没有默认初始化值,必须定义,赋值,然后才能使用。

    2、事件绑定的多种方式

    对于事件的绑定,可以使用的方式有很多,在不同的情况下不同的方式也有不同的优势与局限性,可以根据自己的需求进行自行选择

    • 使用方法名通过+=来添加方法,可以通过-=来删除方法

    • 使用匿名方法

    • 使用Lambda表达式

    关于第一种方法,已经在上面表示的很清楚。

    关于社会的进步与发展,某一方面来讲,是由于人类的懒来驱动的,C#开发人员可能觉得第一种方式太复杂了,于是就出现匿名函数的脚本,先通过代码来看一下其实现方式:

    public class DemoDelegate{    delegate void TestDel(string str);    TestDel Del;    static void Main(string[] args)    {        DemoDelegate demo = new DemoDelegate();        //匿名方法使用方式演示        demo.Del = delegate (string str)        {            Console.WriteLine("这是一个匿名方法的测试");        };            }}

    通过上面的代码可以看出,通过匿名方式使得我们不需要重新定义方法来进行绑定,只需要通过委托关键字,而省去数据类型修饰符、方法签名等结构

    匿名方法定义(菜鸟教程):

    匿名方法提供了一种传递代码块作为委托参数的技术。匿名方法是没有名称只有主体的方法。在匿名方法中不需要指定返回类型,它是从方法主体内的 return 语句推断的()

    而Lambda 表达式更加极致,将能省掉的东西全部省掉,使得最终的表达式极其的简洁:

    public class DemoDelegate    {        delegate void TestDel(string str);        TestDel Del;        static void Main(string[] args)        {            DemoDelegate demo = new DemoDelegate();       //lambda表达式,括号内为参数变量名,如果没有直接()            demo.Del += (str)=>            {                Console.WriteLine(str);            };               }    }

    可以通过脚本看出,Lambda 表达式对于语法的节省到达了极致,去掉了所有的修饰符,包括传入的参数的数据类型修饰符,只需要一个变量名即可,而一个委托如果没有参数,直接使用()即可,简单到极致

    注意(关于()的应用):

    如果Lambda 无参数,则必须要有()
    有一个参数可以去掉(),直接+= str=>{};
    如果有多个参数,也必须要有()

    三、委托的几种特殊实现方式

    除了使用delegate关键字来实现委托外,C#还提供了几种升级版的集成化的使用方式,比如Action和Func方法等等。但是注意,高的集成化往往意味着低的适配性。所以对于下面介绍几种方式他们往往有一定的使用限制,不如delegate来的灵活,不过对于特定场景更加的简单快捷

    1,使用Action方法

    在开始介绍使用方式之前,先说明一下其使用特殊

    • 对于没有返回值的委托,简单的理解就是不需要return(这种想法是错误的,但是好理解)

    其实很简单的对不对,其脚本实现更加简单:

    //无参数的Action委托对象的定义Action<> actDemoOne;//带参数的Action委托对象的定义,参数最多十六个Action<int> actDemoTwo;

    除了定义不同外,创建的委托实例对于方法的绑定与执行与标准的委托相同,其实Action本来就是通过delegate来定义的一个委托类型,但是这个定义是C#系统进行定义的。

    在代码中我们很容易找到这句定义

    C#中委托的基础介绍与实现方法

    而带参数的类型与上面类似

    C#中委托的基础介绍与实现方法

    这样我们可以直接使用C#提供定义好的委托类型来创建我们的委托实例,这种方式的优势就是代码结构简洁好用。不过限制就是只能绑定没有返回值的方法

    2,使用Func方法

    其实Func的用法是与Action相反互补的,其主要的特点是有返回值,为了突出,依旧列出来

    • 主要用于没有参数的委托类型,且必须有返回值

    • 但是同时是可以有参数的,并不是与Action完全相反

    通过代码来表述这一特点:

    // int为该委托绑定方法的返回值类型,注意必须要有返回值Func<int> funDemo;//绑定与执行与标准委托相同,来复习一下public class DemoDelegate{        static void Main(string[] args)        {             DemoDelegate demo = new DemoDelegate();                        Func<int> funDemo;            //为委托添加方法            funDemo = demo.TestEventOne;            //执行委托            funDemo?.Invoke();            //依旧可以使用Lambda表达式            funDemo += () =>            {                return 0;            };                                    Func<string,int> funDemoTwo;            funDemoTwo = demo.TestEventTwo;                    }            public int TestEventOne()        {            return 0;        }        public int TestEventTwo(string str)        {            Console.WriteLine(str);            return 0;        }       }

    上面的代码将两种情况放在一起解释的,可以分开逻辑进行理解,但是重要的是要理解带参数的Func的用法,我们可以看到Func<string,int>有两个数据类型的写入,前面一个就是传入参数的类型,而后面就是返回值类型,一定要区分开来

    四、委托的一些特殊小知识

    1、委托闭包的产生

    在正式开始介绍闭包概念之前,先通过一个案例来发掘关于闭包产生的现象,你可以猜想一下下面的代码的输出结果:

    class DemoDelegate    {        delegate void TestDel();        TestDel Del;        static void Main(string[] args)        {            DemoDelegate demo = new DemoDelegate();                 for (int i = 0; i < 3; i++)            {                demo.Del+= () =>                {                    Console.WriteLine(i);                };            }            demo.Del?.Invoke();    }    }

    如果根据正常的逻辑思路去判断,会很直接的判断得到的输出为:0、1、2,但是经过执行打印却发现最终的输出结果为:3、3、3(为啥不是2、2、2,思考一下++i与i++,或者往后看)

    这样的结果确实很奇妙,但是如果认真思考,你可能会有一些小想法,是不是由于存储的是数据i地址呢,而导致最终结果相同呢。其实可以简单的理解成这个样子。

    如果想要更加深入的了解闭包,希望下面的一些解释可以帮助你理解

    闭包概念:

    是一个函数与其他相关引用环境组合的实体,而在引用环境消失后,该函数会依旧保存从函数内引用的变量

    根据上面的例子来翻译一下就是委托的代码块使用了代码块外的变量,而这个变量是Test()方法的局部变量,当Test()方法执行完毕后,这个局部变量本应该被销毁,但是由于闭包原因却保存其状态到内存中,来保证自己后续的使用。

    因此,所有的委托方法需要的变量内存地址都指向了本应被销毁的局部变量i,最终的读取就是i最后的状态,也就是全是经过三次i++后的3

    闭包需要注意的问题

    如果使用必要,需要注意由于闭包而产生的内存泄露的问题,由于闭包是访问另一个函数中的变量,就会影响另一函数中的局部变量的内存回收。而一直占用在内存中。造成内存泄露的后果。

    但是也有另外的观点讲闭包不会造成内存泄露。原因在于C#的垃圾回收是有相应的处理的。由于本人对于垃圾回收机制认识比较浅显,目前也做不出判断。还希望了解的人可以留言告知

    2,关于事件

    在C#中,也提出了事件这个概念,本质上来讲也是委托,但是是一个受限的委托

    与灵活的委托不同,事件只能在定义的类内被调用,不过可以在其他类里面进行方法的绑定

    事件的用法

    在我们定义一个委托类型后,我们可以通过event创建一个事件实例:

    C#中委托的基础介绍与实现方法

    通过上面的案例可以看到,使用event修饰委托实例后,只能够在定义类中执行委托的方法,而不能在其他类中去调用执行

    感谢各位的阅读,以上就是“C#中委托的基础介绍与实现方法”的内容了,经过本文的学习后,相信大家对C#中委托的基础介绍与实现方法这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    C#中委托的基础介绍与实现方法

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档

    猜你喜欢

    C#中委托的基础介绍与实现方法

    这篇文章主要讲解了“C#中委托的基础介绍与实现方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C#中委托的基础介绍与实现方法”吧!目录前言关于委托委托的实现一、基本实现方式二、使用委托时的
    2023-06-20

    C#中委托的概念与使用方法是什么

    本篇内容主要讲解“C#中委托的概念与使用方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#中委托的概念与使用方法是什么”吧!委托的概念委托这个名字取的神乎其神的,但实质是函数式编程,把
    2023-07-05

    C++中POCO库的安装与基础知识介绍(Windwos和Linux)

    这篇文章主要为大家介绍了C++POCO库的简单介绍、下载以及安装方式、简单代码示例,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2023-05-19

    介绍在Golang中实现字符串转换为数字的方法

    Golang中字符串转数字的方法介绍,需要具体代码示例在Golang中,将字符串转换为数字是一种常见的操作,可以用于处理用户输入的表单数据、配置文件读取等场景。本文将介绍几种常用的字符串转数字的方法,并提供相应的代码示例。使用strco
    介绍在Golang中实现字符串转换为数字的方法
    2024-01-16

    C++中线程的原理与实现方法是什么

    这篇文章主要介绍“C++中线程的原理与实现方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C++中线程的原理与实现方法是什么”文章能帮助大家解决问题。在C++中有多种实现线程的方式C++11
    2023-07-05

    Java/Go/Python/JS/C基数排序算法的原理与实现方法是什么

    这篇文章主要介绍“Java/Go/Python/JS/C基数排序算法的原理与实现方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java/Go/Python/JS/C基数排序算法的原理与实现
    2023-07-05

    C++中多态性实现的问题与解决方法概述

    C++中多态性实现的问题与解决方法概述引言:在C++中,多态性是一种重要的特性,它允许我们在编译时不确定某个对象的真正类型,而在运行时根据实际的类型进行相应的操作。然而,实现多态性也会面临一些问题,本文将简要介绍这些问题,并提供一些解决方法
    2023-10-22

    phpcms关于url路由在二次开发中的使用方法介绍-实现泛解析

    首先,路由是负责将用户请求映射到特定的 MVC 控制器操作.v9默认的路由文件是 caches\configs\route.php ,默认路由如下: 复制代码代码如下: 'default'=>array('m'=>'content',
    2022-06-12

    笔记本电脑中的Win7/Win8系统下无法实现自动待机屏保问题分析解决方法介绍

    Win7/Win8系统的笔记本可以在菜单里手动点击进入睡眠、休眠的状态,但是无法自动进入睡眠、待机状态、屏保,电源选项中设置正常。原因分析: 当开启演示模式后,电脑将保持唤php醒的状态,此时电脑不会自动进入睡眠、休眠状态,屏幕亮javas
    2023-05-31

    win8系统中的管理无线网络工具在哪里?用命令实现无线网络管理方法介绍

    Windows 8中,“网络和共享中心”取消了“管理无线网络”选项。右下角网络图标,只能显示当前能搜到的热点,如果要管理所有已连接过的概要文件,就比较不方便,只能用命令来实现了。 首先,Win
    2022-06-04

    编程热搜

    • Python 学习之路 - Python
      一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
      Python 学习之路 - Python
    • chatgpt的中文全称是什么
      chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
      chatgpt的中文全称是什么
    • C/C++中extern函数使用详解
    • C/C++可变参数的使用
      可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
      C/C++可变参数的使用
    • css样式文件该放在哪里
    • php中数组下标必须是连续的吗
    • Python 3 教程
      Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
      Python 3 教程
    • Python pip包管理
      一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
      Python pip包管理
    • ubuntu如何重新编译内核
    • 改善Java代码之慎用java动态编译

    目录