【学习资料】

  《C#图解教程》(第13~14章):https://www.cnblogs.com/moonache/p/7687551.html
  电子书下载:https://pan.baidu.com/s/1mhOmBG0

  • 其他

    > 委托与事件详解Part1:http://www.tracefact.net/tech/009.html

    > 委托与事件详解Part2:http://www.tracefact.net/tech/029.html

【内容】

    • 委托(Delegate)

      • 定义:类似C++的函数指针
      • 委托多播
      • 委托绑定函数及执行原理
    • 事件(Event)
      • 定义:类似 字段与属性 的关系
      • 事件访问器(add/remove)
      • 为什么使用事件?

【委托Delegate】

  • 定义

    • 类似C++的函数指针,delegate相当于是 指向某对象的某个函数,的 引用类型变量
    • 委托和类一样,也需要 声明、创建、赋值
      • 声明委托类型(像类一样声明一个委托类型)  public delegate [函数返回值] 委托名称(参数1,参数2...);
      • 创建委托变量  MyDelegate opt = new MyDelegate(AddNum);  (实际绑定的是:this.AddNum)
      • 重新赋值  opt = MultNum;  (实际绑定的是:this.MultNum)
    • 执行委托:就是执行引用的 委托函数
    • 委托可以:动态修改引用的函数
    • // 声明:一个可以指向 返回类型为int,带2个int参数的 函数
      public delegate int MyDelegate(int a, int b); // 相加函数
      public int AddNum(int a, int b)
      {
      return (a + b);
      }
      // 相乘函数
      public int MultNum(int a, int b)
      {
      return (a * b);
      } void Start()
      {
      // 创建:指向不同函数的委托类型
      MyDelegate opt = new MyDelegate(AddNum);
      Debug.Log(opt(, )); // 执行委托函数: 7 // 运行时,可以改变赋值
      opt = MultNum;
      Debug.Log(opt(, )); // 执行委托函数: 10
      }
  • 委托多播

    • 创建的委托类型变量 opt 可以存储 函数调用列表(绑定多个委托函数)
    • 通过 "+",或"+="添加 一个函数引用
    • 通过 "-",或"-="  :移除 某个函数的引用
    • 执行委托:会执行所有添加绑定的 委托函数
    • public delegate void MyDelegate(int a, int b);
      
      // 输出相加结果
      public void PrintAddNum(int a, int b)
      {
      Debug.Log("PrintAddNum:" + (a + b));
      }
      // 输出相乘结构
      public void PrintMultNum(int a, int b)
      {
      Debug.Log("PrintMultNum:" + (a * b));
      } void Start()
      {
      // 创建:指向不同函数的委托类型
      MyDelegate opt = new MyDelegate(PrintAddNum); // 通过+=添加委托函数
      // 也可以直接相加 opt = PrintAddNum + PrintMultNum;
      opt += PrintMultNum;
      // 执行委托,会按添加的顺序,分别执行PrintAddNum和PrintMultNum
      opt(, ); // 通过-=移除对某函数的引用
      opt -= PrintAddNum;
      // 再次执行委托,只执行了PrintMultNum
      opt(, );
      } // 输出
      // PrintAddNum: 7
      // PrintMultNum: 10
      // PrintMultNum: 10
  • 委托绑定函数及执行原理

    • 绑定委托函数

      • 可以通过:“=”、“+=”、“-=”、“+”、“-”,来重新给委托绑定函数,或添加删除函数
      • 绑定普通函数:同时会将对象(this)引用存储起来
      • 绑定静态函数:无需存储对象(this)引用
      • class Person
        {
        public delegate void MyDelegate(int a, int b);
        public MyDelegate myDelegate; // 普通函数,绑定时需要有明确对象(this)
        public void Func1(int a, int b) { ... }
        // 静态函数,通过类名.Func2绑定
        public static void Func2(int a, int b) { ... }
        } void Start()
        {
        Person myPerson = new Person(); //myPerson.myDelegate += Person.Func1; // 报错,Func1需要对象(this)
        myPerson.myDelegate += Person.Func2; myPerson.myDelegate += myPerson.Func1;
        //myPerson.myDelegate += myPerson.Func2; // 报错,Func2是静态函数
        }
    • 执行方式
      • 通过"+" 或 "+=" 的顺序,依次执行绑定的委托函数
      • 普通函数:相当于 调用 绑定对象引用(this)的函数,包含了对象的this引用
      • 静态函数:相当于 调用 绑定的委托函数;
      • // 声明委托类型
        public delegate void MyDelegate(); class Person
        {
        public string name;
        public void PrintName()
        {
        Debug.Log(name);
        }
        } void Start()
        {
        // 创建2个对象
        Person myPerson = new Person();
        Person myPerson2 = new Person();
        myPerson.name = "Alice";
        myPerson2.name = "Bob"; // 创建委托变量
        MyDelegate myDelegate = new MyDelegate(myPerson.PrintName);
        // 多播:委托函数
        myDelegate += myPerson2.PrintName; // 执行委托
        myDelegate();
        } // 输出
        // Alice
        // Bob

【事件】

  • 定义

    • 事件是对委托的封装,关系和字段与属性(Property) 一样
    • 事件是基于委托,所以首要声明委托,再定义事件
    • // 声明委托类型
      public delegate void MyDelegate(int a, int b);
      // 定义事件
      public event MyDelegate myEvent;
    • 注:事件的声明只能在类内部,不能在函数内
    • 原理
      • 实际上与属性一样,定义一个事件,会自动创建一个隐藏(private)的委托类型变量
      • 并包含了add_xxx("+=")和remove_xxx("-="),用来添加/删除 委托函数
    • 事件的执行:只能在定义事件的类内部执行
    • // 声明委托类型
      public delegate void MyDelegate(int a, int b); class Person
      {
      // 定义事件
      public event MyDelegate myEvent; public void FireEvent(int a, int b)
      {
      if (myEvent != null)
      myEvent(a, b); // 必须在定义事件的类内部执行
      }
      } public void PrintAddNum(int a, int b)
      {
      Debug.Log("PrintAddNum:" + (a + b));
      }
      public void PrintMultNum(int a, int b)
      {
      Debug.Log("PrintMultNum:" + (a * b));
      } void Start()
      {
      Person person = new Person();
      person.myEvent += PrintAddNum;
      person.myEvent += PrintMultNum; //person.myEvent(2, 5); // 报错,无法在定义事件的类外部执行
      person.FireEvent(, ); // 正确
      }
    • 注:事件不能在类的外部使用赋值“=”,但是在类内部可以重新赋值“=”
    • 事件与委托一样,也支持多播:可以通过“+=”、“-=” 来添加事件、删除事件
  • 事件访问器(add / remove)

    • 事件与委托的关系,与 字段与属性的关系是一样的,所以也有访问器
    • 关键字: add  remove 
    • public event MyDelegate myEvent
      {
      add
      {
      ... //执行 += 运算符的代码
      }
      remove
      {
      ... //执行 -= 运算符的代码
      }
      }
  • 为什么使用事件?

    • 对委托的封装

      • 对外只能通过事件来 添加/删除 绑定的委托函数
      • 事件只能在定义事件的 类内部执行
    • 满足观察者模式(发布者-订阅者)
    • 当然不使用事件,也可以实现对委托的封装
      • 将委托定义为private,然后对外提供添加/删除委托函数的方法(相当于手动实现事件中的add_xxx和remove_xxx)
      • // 声明委托类型
        public delegate void MyDelegate(int a, int b); class Person
        {
        // 定义一个私有委托变量
        public MyDelegate myDelegate;
        // 添加
        public void AddEvent(MyDelegate d)
        {
        myDelegate += d;
        }
        // 删除
        public void RemoveEvent(MyDelegate d)
        {
        myDelegate -= d;
        }
        // 执行
        public void FireEvent(int a, int b)
        {
        if (myDelegate != null)
        myDelegate(a, b); // 必须在定义事件的类内部执行
        }
        } public void PrintAddNum(int a, int b)
        {
        Debug.Log("PrintAddNum:" + (a + b));
        }
        public void PrintMultNum(int a, int b)
        {
        Debug.Log("PrintMultNum:" + (a * b));
        } void Start()
        {
        Person person = new Person(); person.AddEvent(PrintAddNum); // this.PrintAddNum
        person.RemoveEvent(PrintMultNum); // this.PrintMultNum person.FireEvent(, );
        }

【Unity|C#】基础篇(8)——委托(Delegate)/ 事件(Event)的更多相关文章

  1. C#基础篇 - 理解委托和事件

    1.委托 委托类似于C++中的函数指针(一个指向内存位置的指针).委托是C#中类型安全的,可以订阅一个或多个具有相同签名方法的函数指针.简单理解,委托是一种可以把函数当做参数传递的类型.很多情况下,某 ...

  2. C# 篇基础知识5——委托和事件

    事件处理程序是基于“委托”机制运行的. 1.委托 (1)委托的定义和使用 有时需要将一个函数作为另一个函数的参数,这时就要用到委托(Delegate)机制.例如设计一个马戏表演函数: //定义委托 d ...

  3. 秒杀多线程第六篇 经典线程同步 事件Event

    原文地址:http://blog.csdn.net/morewindows/article/details/7445233 上一篇中使用关键段来解决经典的多线程同步互斥问题,由于关键段的“线程所有权” ...

  4. 转--- 秒杀多线程第六篇 经典线程同步 事件Event

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇 一个经典的多线程同步问题> <秒杀多线程第五篇 经典线程同步关键段CS> 上一篇中使用关键段来解决经典的多线程同步互斥问题 ...

  5. js 基础篇(点击事件轮播图的实现)

    轮播图在以后的应用中还是比较常见的,不需要多少行代码就能实现.但是在只掌握了js基础知识的情况下,怎么来用较少的而且逻辑又简单的方法来实现呢?下面来分析下几种不同的做法: 1.利用位移的方法来实现 首 ...

  6. (spring-第15回【IoC基础篇】)容器事件

    五个人在报社订阅了报纸.报社一旦有了新报纸,就派员工分别送到这五个人手里.在这个例子中,“报纸”就是事件,“报社”就是广播器,五个订阅者就是监听器.广播器收到事件,把事件传给监听器,监听器对事件做一些 ...

  7. 自动化测试基础篇--Selenium鼠标键盘事件

    摘自https://www.cnblogs.com/sanzangTst/p/7477382.html 前面几篇文章我们学习了怎么定位元素,同时通过实例也展示了怎么切换到iframe,怎么输入用户名和 ...

  8. Unity 3D观察者设计模式-C#委托和事件的运用

    C#观察者设计模式 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享.心创新! ...

  9. cocos2dx基础篇(7) 触碰事件

    cocos2dx游戏引擎的重点是在于移动设备的跨平台开发,而移动设备上的游戏大部分都是通过屏幕触碰来进行的.比如主菜单的按钮触碰,打飞机中飞机的触碰移动,都需要用到触碰操作.想一想之前讲的菜单按钮CC ...

随机推荐

  1. VAR 学习笔记3

    脉冲响应图及方差分析 当使用VAR模型的时候需要完成: 选择合适的变量 就是研究变量这个没有疑问 判断滞后阶数 根据AIC和SC准则,选择 为何做格兰杰因果检验 如果给定 \(x_t\) 的滞后阶数, ...

  2. 『后缀自动机入门 SuffixAutomaton』

    本文的图片材料多数来自\(\mathrm{hihocoder}\)中详尽的\(SAM\)介绍,文字总结为原创内容. 确定性有限状态自动机 DFA 首先我们要定义确定性有限状态自动机\(\mathrm{ ...

  3. HTML概念、语法及常用基础标签

    HTML基础语法 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  4. 第7章.字符串、String类和StringBuilder类

    参考链接: https://www.runoob.com/csharp/csharp-string.html https://www.cnblogs.com/cang12138/p/7323709.h ...

  5. beego flash 数据

    flash 数据 这个 flash 与 Adobe/Macromedia Flash 没有任何关系.它主要用于在两个逻辑间传递临时数据,flash 中存放的所有数据会在紧接着的下一个逻辑中调用后清除. ...

  6. API接口幂等性设计

    目录 幂等性场景 解决方案 幂等性场景 网络延迟导致多次重复提交. 表单重复提交. 解决方案 每次提交都使用一个Token,Token保证临时且唯一即可 token生成规则(单机应用):token+U ...

  7. MVC开发模式以及Smarty模板引擎的使用

    Linux 全局安装 composer 将目录切换到/usr/local/bin/目录 cd /usr/local/bin/ 在 bin 目录中下载 composer curl -sS https:/ ...

  8. 婴儿潮一代\千禧一代\X一代\Z一代含义

    (一)婴儿潮一代 婴儿潮一代是指各国的生育高峰期.每个时期的婴儿潮一代都会给各国经济带来不小的刺激作用,但同样的当他们退休时也会给政府的养老保险带来巨大的压力. 在中国,从统计数据来看生育高峰出现在1 ...

  9. PAT (Advanced Level) Practice 1120 Friend Numbers (20 分) (set)

    Two integers are called "friend numbers" if they share the same sum of their digits, and t ...

  10. 08-SV面向对象编程的高级技巧指南

    1.原始类与扩展类 (1)原始类被称为父类或者超类,扩展类被称为派生类或者子类.扩展类可以直接访问原始类和其本身的所有变量,应该将原始类中的子程序定义成虚拟的,这样它们就可以在扩展类中重定义.new函 ...