【从零开始入门unity游戏开发之——C#篇33】C#委托(`Delegate`)和事件(`event` )、事件与委托的区别、Invoke()的解释

news2025/1/3 19:39:27

文章目录

  • 一、委托(`Delegate`)
    • 1、什么是委托?
    • 2、委托的基本语法
    • 3、定义自定义委托
    • 4、如何使用自定义委托
    • 5、多播委托
    • 6、C# 中的系统委托
    • 7、`GetInvocationList` 获取多个函数返回值
    • 8、总结
  • 二、事件(`event` )
    • 1、事件是什么?
      • 1.1. **事件是基于委托的存在**:
      • 1.2. **事件是委托的安全包裹**:
      • 1.3. **事件是一种特殊的变量类型**:
    • 2、事件的使用
      • 2.1 **声明事件语法**:
      • 2.2 **事件的使用**:
      • 2.3 **事件的触发**:
    • 3、**委托与事件的区别**:
    • 4、为什么要使用事件?
      • 4.1. **防止外部随意置空委托**:
      • 4.2. **防止外部随意调用委托**:
      • 4.3. **事件封装了委托,增强了安全性**:
    • 5、事件与委托的区别总结
      • 5.1. **赋值操作**:
      • 5.2. **调用方式**:
      • 5.3. **临时变量**:
      • 5.4. **可见性和封装**:
    • 6、总结
  • 三、补充`Invoke()`的解释说明
  • 专栏推荐
  • 完结

一、委托(Delegate

1、什么是委托?

委托(Delegate)是 C# 中的一个重要概念,它可以被理解为“函数(方法)的容器”。更具体地说,委托是用来存储、传递函数(方法)的类型,允许我们将方法作为参数传递给其他方法或存储在变量中。委托的本质是一个类,用来定义方法的类型(即方法的返回值和参数类型)。

  • 委托本质上是一个类型,它定义了方法的类型:返回值类型和参数类型。
  • 委托用于存储方法,它帮助你把方法传递给其他方法,或者在程序中动态调用。
  • 委托是一个引用类型

2、委托的基本语法

  1. 关键字: delegate

  2. 语法:

     [访问修饰符] delegate 返回值类型 委托名(参数列表);
    

    示例:

    delegate void MyDelegate(); // 无返回值,无参数的委托
    delegate int MyDelegateWithParam(int x); // 返回 int,带一个参数的委托
    
  • 委托可以声明在类(class)或命名空间(namespace)中,一般情况下会声明在命名空间中。
  • 委托声明的访问修饰符可以是 public(默认是 public),也可以是 privateprotectedinternal 等。

3、定义自定义委托

  1. 无参无返回值的委托

    public delegate void MyFun();
    
  2. 带参数和返回值的委托

    public delegate int MyFun2(int a);
    
  3. 泛型委托:
    委托是支持泛型的,可以让返回值和参数的类型灵活变更。

    delegate T MyFun3<T, K>(T v, K k);
    

4、如何使用自定义委托

委托变量相当于一个函数的容器,可以存储函数,并通过委托来调用它。

  1. 基本用法

    • 通过 new 关键字创建委托实例,并调用它。
    public delegate void MyFun();
    
    static void Fun()
    {
        Console.WriteLine("Hello from Fun!");
    }
    
    static void Main(string[] args)
    {
        MyFun f = new MyFun(Fun); // 创建委托实例
        f.Invoke();  // 调用委托,输出: Hello from Fun!
    }
    
  2. 简化方式(委托隐式转换)
    委托可以直接引用方法,而不需要 new 操作符。

    MyFun f2 = Fun;
    f2(); // 调用 Fun() 方法
    
  3. 带参数的委托
    如果委托方法需要参数,可以在调用时传递参数。

    public delegate int MyFun2(int a);
    
    static int Fun2(int x)
    {
        return x * 2;
    }
    
    static void Main(string[] args)
    {
        MyFun2 f3 = Fun2;
        Console.WriteLine(f3(3)); // 输出: 6
    }
    
  4. 委托作为参数
    委托经常作为方法的参数,用于传递行为。

     public delegate void MyFun(); // 定义委托类型
     
     class Test()
     {
         public void TestFun(MyFun fun)
         {
             // 执行其他逻辑
             fun();  // 调用传入的委托方法
         }
     }
     
     class Program
     {
         static void FunLog()
         {
             Console.WriteLine("Hello from Fun!");
         }
     
         public static void Main()
         {
             MyFun Fun = FunLog; // 创建委托实例
     
             Test t = new Test();
             t.TestFun(Fun); // 传递委托
         }
     }
    

    结果打印
    在这里插入图片描述

5、多播委托

委托可以存储多个方法(多播委托)。通过多播委托,可以在一个委托实例中注册多个方法,调用时按顺序执行这些方法。

  1. 添加多个方法到委托

    MyFun f = Fun;
    f += Fun2;
    f();  // 调用 Fun 和 Fun2 方法
    
  2. 移除方法

    f -= Fun;
    f();  // 只调用 Fun2 方法
    
  3. 清空所有注册的方法

    f = null;
    

6、C# 中的系统委托

C# 提供了多个预定义的委托类型,主要有 ActionFunc。这些委托可以大大简化我们的编程工作。

  1. Action 委托
    Action 委托用于没有返回值的情况。它可以有0到16个参数。

    Action委托的语法结构

    Action<参数类型1, 参数类型2, ..., 参数类型N>
    
    • 无参数:

      Action action = Fun;
      action += Fun2;
      action();// 调用 Fun 和 Fun2 方法
      
    • 带参数:

      Action<int, string> action2 = Fun2;
      action2(1, "Hello");
      
  2. Func 委托
    Func 委托用于有返回值的情况。它也支持0到16个参数。
    Func 委托的最后一个类型参数总是方法的返回值类型,而其他的参数类型则是方法的输入参数类型。

    Func 委托的语法结构

    Func<参数类型1, 参数类型2, ..., 参数类型N, 返回值类型>
    
    • 无参数,有返回值:

      static int FunLog()
      {
         return 1;
      }
      
      public static void Main()
      {
         Func<int> func = FunLog;
         int result = func();
         Console.WriteLine(result);// 打印1
      }
      
    • 带参数,有返回值:

         static int FunLog(string str)
         {
             return int.Parse(str);
         }
      
         public static void Main()
         {
             Func<string, int> func = FunLog;
             int result = func("111");
             Console.WriteLine(result);// 打印111
         }
      

7、GetInvocationList 获取多个函数返回值

当用有返回值的委托容器存储多个函数时

using System;

class Program
{
    static void Main()
    {
        // 创建一个 Func 委托,返回 string 类型
        Func<string> funTest = () =>
        {
            Console.WriteLine("第一个函数");
            return "1";
        };

        // 将更多函数添加到委托链
        funTest += () =>
        {
            Console.WriteLine("第二个函数");
            return "2";
        };

        funTest += () =>
        {
            Console.WriteLine("第三个函数");
            return "3";
        };

        // 如果直接调用委托,会执行所有函数逻辑,但是只能获取到最后一个返回值
        Console.WriteLine("直接调用返回值:");
        Console.WriteLine(funTest());  // 只会输出 "3"
    }
}

输出结果:

直接调用返回值:
第一个函数
第二个函数
第三个函数
3

如果想要获取每个函数的返回值,可以通过 GetInvocationList 方法

foreach (Func<string> del in funTest.GetInvocationList())
{
    Console.WriteLine(del());  // 输出每个函数的返回值
}

输出结果:

第一个函数
1
第二个函数
2
第三个函数
3
  • funTest.GetInvocationList() 返回一个委托数组,数组中的每个元素都是一个 Func 委托实例,表示容器中每个方法。
  • 我们通过 foreach 遍历这些委托实例,并单独执行每个方法,获取它们的返回值。

8、总结

  • 委托 是 C# 中用来装载方法的类型,允许将方法作为参数传递或者存储。
  • 委托的定义语法包括 delegate 关键字,后接返回类型、委托名称以及参数列表。
  • 委托支持泛型,可以创建灵活的、可重用的函数容器。
  • 委托可以作为方法的参数,或作为类的成员变量,用于实现事件、回调等功能。
  • C# 提供了 没有返回值Action 和 有返回值Func 等预定义的委托类型,可以减少开发者手动定义委托的工作量。

二、事件(event

在 C# 中,事件是基于委托的,它对委托进行了封装,提供了一些安全性和约束。事件是 C# 中一种特殊的成员,通常用于发布-订阅模式,允许一个对象(发布者)通知其他对象(订阅者)某些事情的发生。

1、事件是什么?

1.1. 事件是基于委托的存在

  • 委托可以理解为对方法的引用,而事件是基于委托的,委托在事件中扮演着核心角色。

1.2. 事件是委托的安全包裹

  • 事件通过封装委托,限制了委托的使用,使其更具安全性。特别是防止外部代码随意更改委托(赋值和调用)。

1.3. 事件是一种特殊的变量类型

  • 在 C# 中,事件是一种特殊的变量,它用于存储委托类型的引用,但它具有一些额外的限制。

2、事件的使用

2.1 声明事件语法

事件的声明语法如下:

[访问修饰符] event 委托类型 事件名;

例如:

public event Action MyEvent;

2.2 事件的使用

  • 事件作为类的成员变量,类似于委托。
  • 事件和委托的使用方法非常相似,主要的区别在于事件增加了访问限制。

示例:

public class Test
{
    public Action MyFun;  // 委托类型成员变量
    public event Action MyEvent;  // 事件类型成员变量
}

2.3 事件的触发

  • 事件的触发只能在事件的拥有者(类)内部进行,通过调用事件处理方法。
  • 一般来说,可以通过一个方法来触发事件,例如:
public void DoEvent()
{
    if (MyEvent != null)
    {
        MyEvent.Invoke();  // 安全地触发事件
    }
}

3、委托与事件的区别

  • 事件不能在类外部赋值:委托可以在类外部进行赋值(例如:myFun = TestFun),但事件只能通过 +=-= 操作符来添加和移除事件处理器。
  • 事件不能在类外部调用:委托可以在类外部直接调用(例如:myFun()),而事件只能在类内部触发(通常使用事件发布方法)。

示例:

public void TestFun()
{
    Console.WriteLine("123");
}

// 委托使用
myFun += TestFun;
myFun();  // 调用委托

// 事件使用
myEvent += TestFun;  // 添加事件处理器
myEvent();  // 错误,无法在类外部调用事件

4、为什么要使用事件?

4.1. 防止外部随意置空委托

  • 事件的最大优势之一是它防止了外部代码直接修改委托的值(置空)。这保证了事件的安全性,防止委托被外部代码随意设置为 null 或重新赋值,避免了潜在的错误。

4.2. 防止外部随意调用委托

  • 事件提供了对委托的封装,确保事件只能通过 +=-= 操作符来添加和移除事件处理器,不能通过外部代码直接调用。

4.3. 事件封装了委托,增强了安全性

  • 事件是一种委托的封装,提供了更高的安全性和可控性,使得事件处理过程更加规范。外部代码无法直接修改事件的内容,只能通过规范的方式来订阅和退订事件。

5、事件与委托的区别总结

5.1. 赋值操作

  • 委托:可以在外部赋值(=)。
  • 事件:不能直接赋值,只能通过 +=-= 操作符来添加和移除事件处理器。

5.2. 调用方式

  • 委托:可以在外部直接调用(myFun())。
  • 事件:只能在类内部通过触发方法调用(MyEvent.Invoke())。

5.3. 临时变量

  • 委托:可以作为局部变量在方法中使用。
  • 事件:不能作为临时变量,只能作为类的成员存在。

5.4. 可见性和封装

  • 委托:没有访问控制的封装机制,外部可以自由操作。
  • 事件:有封装,提供了更严格的访问控制,确保安全性。

6、总结

  • 事件本质上是一个委托的封装,提供了额外的安全性。它限制了委托在外部的赋值和调用,使得事件的触发只能在拥有事件的类内部进行。
  • 事件的主要用途是实现发布-订阅模式,当某个对象发生变化时,能够通知其他对象,避免外部代码直接修改和调用事件。
  • 事件与委托的主要区别在于访问权限的控制,事件通过严格的封装和访问控制来增强安全性,避免外部随意操作。

三、补充Invoke()的解释说明

Invoke() 是委托事件中常用的方法,它的作用是调用委托所指向的方法。当你在委托或者事件上调用 Invoke() 时,它会执行该委托或事件注册的所有方法。

示例:

public delegate void MyDelegate(string message);

public class Program
{
    static void Main()
    {
        MyDelegate myDelegate = new MyDelegate(PrintMessage);
        myDelegate.Invoke("Hello, World!");  // 调用委托的 Invoke 方法
    }

    static void PrintMessage(string message)
    {
        Console.WriteLine(message);
    }
}

Invoke() 是隐式调用的,因此你也可以直接使用 myDelegate() 来调用它。这两者的作用是相同的。实际上,Invoke() 是自动由 C# 编译器生成的,如果你使用 myDelegate(),编译器会在幕后调用 Invoke()

对于事件同理,Invoke() 方法用于触发事件并调用所有注册的事件处理程序。事件本质上是封装了委托,因此通过 Invoke() 可以调用所有订阅该事件的方法。


专栏推荐

地址
【从零开始入门unity游戏开发之——C#篇】
【从零开始入门unity游戏开发之——unity篇】
【制作100个Unity游戏】
【推荐100个unity插件】
【实现100个unity特效】
【unity框架开发】

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!如果你遇到任何问题,也欢迎你评论私信或者加群找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2268770.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大模型—Ollama 结构化输出

Ollama 结构化输出 Ollama现在支持结构化输出,使得可以按照由JSON模式定义的特定格式来约束模型的输出。Ollama的Python和JavaScript库已经更新,以支持结构化输出。 结构化输出的用例包括: 从文档中解析数据从图像中提取数据结构化所有语言模型响应比JSON模式更可靠和一致开…

【Python】selenium 获取滑块和背景图在电脑屏幕的相对位置【解决滑块验证码问题】

在使用python模拟爬取的时候&#xff0c;解决滑动验证码是不可缺少的环节。怎么解决滑动验证码的问题呢&#xff0c;我们可以试着使用这样的方法&#xff1a; 我们在解决滑块验证码问题的时候&#xff0c;首先要找到滑块和在网页上的位置&#xff0c;定位好位置以后&#xff0…

微信小程序:定义页面标题,动态设置页面标题,json

1、常规设置页面标题 正常微信小程序中&#xff0c;设置页面标题再json页面中进行设置&#xff0c;例如 {"usingComponents": {},"navigationBarTitleText": "标题","navigationBarBackgroundColor": "#78b7f7","navi…

Visual Studio 中增加的AI功能

前言&#xff1a; 人工智能的发展&#xff0c;在现在&#xff0c;编程技术的IDE里面也融合了AI的基本操做。本例&#xff0c;以微软的Visual Studio中的人工智能的功能介绍例子。 本例的环境&#xff1a; Visual Studio 17.12 1 AI 智能变量检测&#xff1a; 上图展示了一…

后端开发-Maven

环境说明&#xff1a; windows系统&#xff1a;11版本 idea版本&#xff1a;2023.3.2 Maven 介绍 Apache Maven 是一个 Java 项目的构建管理和理解工具。Maven 使用一个项目对象模型&#xff08;POM&#xff09;&#xff0c;通过一组构建规则和约定来管理项目的构建&#xf…

BAPI_BATCH_CHANGE在更新后不自动更新批次特征

1、问题介绍 在CL03中看到分类特性配置了制造日期字段&#xff0c;并绑定了生产日期字段MCH1~HSDAT MSC2N修改批次的生产日期字段时&#xff0c;自动修改了对应的批次特性 但是通过BAPI&#xff1a;BAPI_BATCH_CHANGE修改生产日期时&#xff0c;并没有更新到批次特性中 2、BAPI…

ARM200~500部署

前提&#xff1a;数据库已经安装好&#xff0c;并且正常运行 1.修改hostname,将里面的AR-A 改为hzx vi /etc/hostname 2.重启网络服务 sudo systemctl restart NetworkManager 3.修改community-admin.service 文件&#xff0c;更改小区名称和IP&#xff0c;并将文件上传到/…

修改secure-file-priv参数-mysql5.7.26限制不允许导入或导出的解决方法

文章目录 前言secure_file_priv参数说明修改secure_file_priv参数的步骤 前言 本人是在sql注入的文件上传拿web shel 时所用到的写入文件权限遇到文件上传不成功的问题&#xff0c;记住修改后&#xff0c;重启mysql才生效&#xff0c;最后可以查看验证一下。 secure_file_priv…

Java编程规约:日期时间

文章目录 I 日期时间编程规约【强制】【推荐】II 知识扩展日期格式I 日期时间编程规约 【强制】 日期格式化时,传入 pattern 中表示年份统一使用小写的 y。说明:日期格式化时,yyyy 表示当天所在的年,而大写的 YYYY 代表是 week in which year(JDK7 之后引入的概念), 意…

Java [后端] 开发日常记录(1)

目录 1、常用的注解 2、对字符串的处理 3、对JSON串的处理 -- The End -- 详细如下&#xff1a; 1、常用的注解 若返回的字段中有NUll&#xff0c;则不返回 JsonInclude(value JsonInclude.Include.NON_NULL) //在实体类中添加这个注解 JsonInclude(JsonInclude.Include.NON…

LabVIEW声波谐振管自动化测量系统

开发了一种基于LabVIEW的声波谐振管自动化测量系统。该系统利用LabVIEW的强大功能&#xff0c;实现了对声波谐振频率的精确测量&#xff0c;提高了实验数据的采集效率和准确性。系统主要应用于物理教学和科研中&#xff0c;用于研究声波在谐振管中的传播特性。 项目背景 传统的…

2024/12/29 黄冈师范学院计算机学院网络工程《路由期末复习作业一》

一、选择题 1.某公司为其一些远程小站点预留了网段 172.29.100.0/26&#xff0c;每一个站点有10个IP设备接到网络&#xff0c;下面那个VLSM掩码能够为该需求提供最小数量的主机数目 &#xff08; &#xff09; A./27 B./28 C./29 D./30 -首先审题我们需要搞清楚站点与网…

el-table动态行和列及多级表头

主页面 <template><div class"result-wrapper"><dynamic-table :table-data"tableData" :table-header"tableConfig" :tableTitle"tableTitle" :flowParams"flowParams"></dynamic-table></div…

✨✨vue3自定义动态不同UI组件筛选框案例✨

✨1. 实现功能 &#x1f31f;添加条件进行数据筛选 根据筛选数据条件不同&#xff0c;显示不同的UI组件&#xff1a;包含datetime、select、input等筛选完条件可继续添加与取消条件当然可以在条件列表中进行直接删除&#xff0c;当删除完所有条件之后&#xff0c;回到添加条件…

Go+chromedp实现Web UI自动化测试

1.为什么使用go进行UI自动化测试&#xff1f; 速度&#xff1a;Go速度很快&#xff0c;这在运行包含数百个UI测试的测试套件时是一个巨大的优势 并发性&#xff1a;可以利用Go的内置并发性(goroutines)来并行化测试执行 简单&#xff1a;Go的简约语法允许您编写可读且可维护…

总结TCP/IP四层模型

总结TCP/IP四层模型 阅读目录(Content) 一、TCP/IP参考模型概述 1.1、TCP/IP参考模型的层次结构二、TCP/IP四层功能概述 2.1、主机到网络层  2.2、网络互连层  2.3、传输层  2.3、应用层 三、TCP/IP报文格式 3.1、IP报文格式3.2、TCP数据段格式3.3、UDP数据段格式3.4、套…

怎么在家访问公司服务器?

在日常工作中&#xff0c;特别是对信息技术从业者而言&#xff0c;工作往往离不开公司的服务器。他们需要定期访问服务器&#xff0c;获取一些关键的机密文件或数据。如果您在家办公&#xff0c;并且需要处理未完成的任务&#xff0c;同时需要从公司服务器获取所需的数据&#…

自动化文档处理:Azure AI Document Intelligence

Azure AI Document Intelligence支持多种文件格式&#xff0c;包括PDF、JPEG、PNG等。其核心功能是将这些文档按页进行内容提取&#xff0c;并转化为LangChain文档。其默认输出格式是Markdown&#xff0c;这使得文档可以通过MarkdownHeaderTextSplitter进行语义分片。您也可以使…

ubuntu快速入门

1.进入某个文件夹 cd workspace/2.tab自动补全 3.列出当前文件夹所有文件 ls列出所有文件包括隐藏文件 ls -a 4.创建文件夹 mkdir linuxLearn 5.创建文件 gedit command.sh在commmand.sh键入 echo hello echo hi? echo how are you? PS:touch hello.txt(也可以创建新…

在虚幻引擎4(UE4)中使用蓝图的详细教程

在虚幻引擎4&#xff08;UE4&#xff09;中使用蓝图的详细教程 虚幻引擎4&#xff08;Unreal Engine 4&#xff0c;简称UE4&#xff09;是一款功能强大的游戏引擎&#xff0c;广泛应用于游戏开发、虚拟现实、建筑可视化等领域。UE4 提供了一个强大的可视化脚本工具——蓝图&am…