一、前言
1.什么是委托?
委托是一种容器,容器里面放的是函数方法。而函数的形式各不相同,参数,返回值各不相同,所以你做委托之前,先得要定义好这个委托容器存放的函数的类型,即委托类型。
定义了好了函数类型后,将函数加入到委托容器后,你只要触发委托调用,委托就会帮你把容器里面的每个函数都调用一次,触发的时候和调用普通函数没有区别。
2.什么是事件?
事件在类中声明且生成,且通过使用同一个类或其他类中的委托与事件处理程序关联。包含事件的类用于发布事件。这被称为?发布器(publisher)?类。其他接受该事件的类被称为?订阅器(subscriber)?类。事件使用?发布-订阅(publisher-subscriber)?模型。
二、简单案例介绍解析
1.委托
举个例子来使用委托:我们先定义一个宠物名称委托,在TestA类中实现狗和猫的方法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public delegate void PetName(string name); //委托 (需要一个string类型的参数当宠物名称)
//陆地动物类
public class TestA : MonoBehaviour
{
PetName petName; //声明委托
void Start()
{
//委托
petName += Dog; //狗
petName += Cat; //猫
//调用委托事件
petName("大白");
}
//狗 因为委托调用所以需要一个string参数
void Dog(string name)
{
Debug.Log($"我叫{name},是一只猫");
}
//猫
void Cat(string name)
{
Debug.Log($"我叫{name},是一只狗");
}
}
运行结果:
从中我们可以看到,当我们把两个方法(狗,猫)“添加”到委托中时,我们只需要调用定义的委托(petName方法) 就可以同时执行添加的两个方法。根据上面的委托的含义来解释,我们创建了一个petName委托当作容器,然后将dog(狗),cat(猫)方法添加到容器中,这样我们只需要执行容器就可以将容器中的所有方法都给执行。
2.事件
?需要基于上一个委托来实现,我们先创建一个TestB类,里面有两个方法Parrot(string name)鹦鹉、Pigeon(string name)鸽子。同时创建一个Event事件。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//鸟类
public class TestB : MonoBehaviour
{
public static event PetName SayHelloEvent;//事件
void Start()
{
//在事件中添加方法
SayHelloEvent = Parrot;
SayHelloEvent += Pigeon;
SayHelloEvent("小白");
}
//鹦鹉
public static void Parrot(string name)
{
Debug.Log($"我叫{name},是一只鹦鹉");
}
//鸽子
public static void Pigeon(string name)
{
Debug.Log($"我叫{name},是一只鸽子");
}
}
把上一个脚本TestA禁用 将TestB拖入场景运行效果:
三、委托与事件的区别
?委托与事件的使用是一样的,但是事件会有很多限制条件。两者定义与区别如下:
1.委托创建时会定义方法的类型。(是否有无参数、有无返回值)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public delegate void DelegateA(); //无参无返回值
public delegate void DelegateB(string name); //有参无返回值
public delegate string DelegateC(); //无参有返回值
public delegate string DelegateD(string name); //有参有返回值
//陆地动物类
public class TestA : MonoBehaviour
{
//委托定义
DelegateA delegateA; //无参无返回值
DelegateB delegateB; //有参无返回值
DelegateC delegateC; //无参有返回值
DelegateD delegateD; //有参有返回值
void Start()
{
//添加方法
delegateA = A;
delegateB = B;
delegateC = C;
delegateD = D;
//这里错误示范 delegateA委托添加B方法会报错,原因委托定义了方法类型,B方法类型不符合delegateA定义的方法类型会报错
//delegateA += B;
//运行
delegateA();
delegateB("");
delegateC();
delegateD("");
}
void A()
{
Debug.Log("无参无返回值");
}
void B(string name)
{
Debug.Log("有参无返回值");
}
string C()
{
Debug.Log("无参有返回值");
return "";
}
string D(string name)
{
Debug.Log("有参有返回值");
return "";
}
}
运行结果:
?
错误示范:
2.事件的创建需要一个委托才能声明,
3.委托可以在任何类中或类外声明,但是事件只能在类中声明,如下:
4.事件只能在当前声明的类中使用,无论将事件设置成public还是static其他类都无法调用
?总的来说事件Event是一个添加了许多限制的委托。
?四、案例使用
案例一:
举一个大家经常用的例子,你在CSDN中订阅一个博主的专栏(游戏专栏),当这个博主发布了这个专栏的一个最新文章,就会收到消息。这个就是用的委托,实现如下
1.创建一个博主类Blogger,负责书写文章,并且调用委托事件向订阅专栏的用于发送最新文章
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//这是一个博主类负责书写文章,并且调用委托事件向订阅专栏的用于发送最新文章
public class Blogger : MonoBehaviour
{
public InputField articleName; //文章名称
public Button uploadBtn; //上传文章
void Start()
{
//按钮监听
uploadBtn.onClick.AddListener(UpLoad);
}
//上传事件
void UpLoad()
{
//上传文章名称不为空时
if (articleName.text!=string.Empty)
{
Debug.Log($"博主上传文章:{articleName.text}");
}
}
}
?2.创建一个有参无返回值的订阅委托,用于存放订阅人员推送信息方法,并在博主类中声明创建。与上方博主类结合,完整代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public delegate void Subscribe(string name);//订阅委托 用于存放订阅人员的推送方法
//这是一个博主类负责书写文章,并且调用委托事件向订阅专栏的用于发送最新文章
public class Blogger : MonoBehaviour
{
public InputField articleName; //文章名称
public Button uploadBtn; //上传文章
public static Subscribe subscribe; //创建公用的静态订阅委托
void Start()
{
//按钮监听
uploadBtn.onClick.AddListener(UpLoad);
}
//上传事件
void UpLoad()
{
//上传文章名称不为空时
if (articleName.text!=string.Empty)
{
Debug.Log($"博主上传文章:{articleName.text}");
subscribe(articleName.text); //向订阅的人员发送信息
}
}
}
3.新建两个PeopleA、PeopleB人员类,在里面声明Push推送消息方法,并且在strat里添加到订阅委托中?
PeopleA:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//订阅人员A
public class PeopleA : MonoBehaviour
{
void Start()
{
Blogger.subscribe += Push; //向订阅委托中添加人员A的推送方法
}
//推送信息
void Push(string name)
{
Debug.Log($"我是人员A,接收到博主最新文章:{name}");
}
}
PeopleB:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//订阅人员B
public class PeopleB : MonoBehaviour
{
void Start()
{
Blogger.subscribe += Push; //向订阅委托中添加人员A的推送方法
}
//推送信息
void Push(string name)
{
Debug.Log($"我是人员B,接收到博主最新文章:{name}");
}
}
将这三个脚本拖入场景布局如下:
?运行结果:
其他案例:
https://blog.csdn.net/ChinarCSDN/article/details/80387157?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161232462616780255284165%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=161232462616780255284165&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-1-80387157.first_rank_v2_pc_rank_v29_10&utm_term=unity%E4%B8%AD%E5%AE%9A%E4%B9%89delegate%E5%A7%94%E6%89%98%E5%9C%A8%E5%85%B6%E4%BB%96%E8%84%9A%E6%9C%AC%E4%B8%AD%E8%B0%83%E7%94%A8&spm=1018.2226.3001.4187?
|