[Unity] event在Unity中的用法

1,874 阅读3分钟

见前篇[Unity] Action在Unity中的用法

学习BeaverJoe总结。

事件完整声明格式

image.png

!事件是靠委托实现的。

首先声明一个类,周杰伦。

概念实例备注
自定义委托releaseNewAlbumEventHandlerEventHandler事件处理器后缀,是约定俗成的规范
委托变量releaseNewAlbumEventHandler声明一个委托变量
委托注册为事件HasReleaseNewAlbum发售新专辑,这个事件,用ReleaseNewAlbumEventHandler类型的委托实现
添加处理器add{ releaseNewAlbumEventHandler += value; }别人的方法要绑在上面声明的委托变量上
移除处理器remove { releaseNewAlbumEventHandler -= value; }别人的方法从绑在上面声明的委托变量上移除

现在订阅了 「发售新专辑」事件的方法,虽然Jay不知道谁用什么方法订阅了这个事件,但是他在发售新专辑的时候,会调用releaseNewAlbumEventHandler这个委托。

public class JayChou : MonoBehaviour
{
    public static JayChou instance;
    private void Awake()
    {
        instance = this;
    }
    // 定义一个自定义委托,无参数无返回值
    public delegate void ReleaseNewAlbumEventHandler();
    // 声明一个自定义委托变量
    private ReleaseNewAlbumEventHandler releaseNewAlbumEventHandler;

    // 将委托注册为事件
    public event ReleaseNewAlbumEventHandler HasReleaseNewAlbum
    {
        // 添加移除处理器
        // 告诉事件,添加新的方法和移除方法,就是绑定自己的委托,形成多播委托
        add
        {
            releaseNewAlbumEventHandler += value;
        }
        remove
        {
            releaseNewAlbumEventHandler -= value;
        }
    }
    public void Release()
    {
        // 调用委托
        releaseNewAlbumEventHandler?.Invoke();
    }
}

Jay在Instagram上调用发售方法。

public class Instagram : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
            JayChou.instance.Release();
    }
}

不同的类,用不同的方法,订阅了发售新专辑这个事件。

public class FanA : MonoBehaviour
{
    private void OnEnable()
    {
        JayChou.instance.HasReleaseNewAlbum += BuyNewAlbum;
    }
    private void OnDisable()
    {
        JayChou.instance.HasReleaseNewAlbum -= BuyNewAlbum;
    }
    void BuyNewAlbum()
    {
        print("买新CD!");
    }
}
public class FanB : MonoBehaviour
{
    private void OnEnable()
    {
        JayChou.instance.HasReleaseNewAlbum += GoCrazy;
    }
    private void OnDisable()
    {
        JayChou.instance.HasReleaseNewAlbum -= GoCrazy;
    }
    void GoCrazy()
    {
        print("我要在社交媒体上到处转发,终于等到了,要疯了!");
    }
}
public class MilkTeaCompany : MonoBehaviour
{
    private void OnEnable()
    {
        JayChou.instance.HasReleaseNewAlbum += BusinessCooperation;
    }
    private void OnDisable()
    {
        JayChou.instance.HasReleaseNewAlbum -= BusinessCooperation;
    }
    void BusinessCooperation()
    {
        print("找杰伦代言奶茶!");
    }
}

当事件被触发,调用时:

image.png

事件的简略声明格式

效果是一样的。

    // 定义一个自定义委托
    public delegate void ReleaseNewAlbumEventHandler();
    // 用委托声明事件
    public event ReleaseNewAlbumEventHandler HasReleaseNewAlbum;
    // 直接把事件当多播委托用
    public void Release()
    {
        HasReleaseNewAlbum?.Invoke();
    }

用官方准备的事件相关基类:

EventArgs是事件有关参数封装的类,EventHandler相当于委托基类。

    public event EventHandler HasReleaseNewAlbum;
    public void Release(object sender, EventArgs e)
    {
       HasReleaseNewAlbum?.Invoke(sender, e);
    }
    private void GoCrazy(object sender, EventArgs e)
    {
        print("我要在社交媒体上到处转发,终于等到了,要疯了!" + " 来自" + sender as string);
    }
    private void BuyNewAlbum(object sender, EventArgs e)
    {
        print("买新CD!" + " 来自" + sender as string);
    }
    private void BusinessCooperation(object sender, EventArgs e)
    {
        print("找杰伦代言奶茶!" + " 来自" + sender as string);
    }

调用

public class Instagram : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
            JayChou.instance.Release(gameObject.name, EventArgs.Empty);
    }
}

image.png

用Action和Func委托也是可以的。

    //public event EventHandler HasReleaseNewAlbum;
    public event Action<object ,EventArgs> HasReleaseNewAlbum;

具体什么情况,需要什么样的参数,按照什么样的规范,可以灵活应变。总之,最好用事件代替多播委托,会更加规范,限制更严格,不容易出岔子。事件不会允许非“+=、-=”操作符,就是一个包装好的,成熟的多播委托范例。

是 发布者/订阅者模式 或者说 观察者模式 版本的多播委托。

还可以参考C#知识点讲解之C#delegate、event、Action、EventHandler的使用和区别