﻿# 15. 内置工具：TypeEventSystem

QFramework 除了提供了一套架构之外，QFramework 还提供三个可以脱离架构使用的工具 TypeEventSystem、EasyEvent、BindableProperty、IOCContainer。

这些工具并不是有意提供，而是 QFramework 的架构在设计之初是通过这三个工具组合使用而成的。

在这一篇，我们来学习 TypeEventSystem 的使用。

## 基本使用

```csharp
using UnityEngine;

namespace QFramework.Example
{
    public class TypeEventSystemBasicExample : MonoBehaviour
    {
        public struct TestEventA
        {
            public int Age;
        }

        private void Start()
        {
            TypeEventSystem.Global.Register<TestEventA>(e =>
            {
                Debug.Log(e.Age);
            }).UnRegisterWhenGameObjectDestroyed(gameObject);
        }
        
        private void Update()
        {
            // 鼠标左键点击
            if (Input.GetMouseButtonDown(0))
            {
                TypeEventSystem.Global.Send(new TestEventA()
                {
                    Age = 18
                });
            }

            // 鼠标右键点击
            if (Input.GetMouseButtonDown(1))
            {
                TypeEventSystem.Global.Send<TestEventA>();
            }
        }
    }
}

// 输出结果
// 点击鼠标左键，则输出:
// 18
// 点击鼠标右键，则输出:
// 0
```

这就是 TypeEventSystem 的最基本用法。

## 事件继承支持
除了基本用法，TypeEventSystem 的事件还支持继承关系。

示例代码如下:
```csharp
using UnityEngine;

namespace QFramework.Example
{
    public class TypeEventSystemInheritEventExample : MonoBehaviour
    {
        public interface IEventA
        {
            
        }
        
        public struct EventB : IEventA
        {
            
        }

        private void Start()
        {
            TypeEventSystem.Global.Register<IEventA>(e =>
            {
                Debug.Log(e.GetType().Name);
            }).UnRegisterWhenGameObjectDestroyed(gameObject);
        }

        private void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                TypeEventSystem.Global.Send<IEventA>(new EventB());
                
                // 无效
                TypeEventSystem.Global.Send<EventB>();
            }
        }
    }
}


// 输出结果:
// 当按下鼠标左键时，输出:
// EventB
```

代码不难。

## TypeEventSystem 手动注销

如果想控制 TypeEventSystem 的注销，而不是自动注销也很简单，代码如下:

```csharp
using UnityEngine;

namespace QFramework.Example
{
    public class TypeEventSystemUnRegisterExample : MonoBehaviour
    {

        public struct EventA
        {
            
        }
        
        private void Start()
        {
            TypeEventSystem.Global.Register<EventA>(OnEventA);
        }

        void OnEventA(EventA e)
        {
            
        }

        private void OnDestroy()
        {
            TypeEventSystem.Global.UnRegister<EventA>(OnEventA);
        }
    }
}
```

代码也很简单。

## 接口事件

TypeEventSystem 还支持接口事件模式，示例代码如下:

```csharp
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace QFramework.Example
{
    public struct InterfaceEventA
    {
            
    }

    public struct InterfaceEventB
    {
        
    }

    public class InterfaceEventModeExample : MonoBehaviour
        , IOnEvent<InterfaceEventA>
        , IOnEvent<InterfaceEventB>
    {
        public void OnEvent(InterfaceEventA e)
        {
            Debug.Log(e.GetType().Name);
        }
        
        public void OnEvent(InterfaceEventB e)
        {
            Debug.Log(e.GetType().Name);
        }

        private void Start()
        {
            this.RegisterEvent<InterfaceEventA>()
                .UnRegisterWhenGameObjectDestroyed(gameObject);

            this.RegisterEvent<InterfaceEventB>();
        }

        private void OnDestroy()
        {
            this.UnRegisterEvent<InterfaceEventB>();
        }

        private void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                TypeEventSystem.Global.Send<InterfaceEventA>();
                TypeEventSystem.Global.Send<InterfaceEventB>();
            }
        }
    }
}

// 输出结果
// 当按下鼠标左键时，输出:
// InterfaceEventA
// InterfaceEventB
```

代码很简单。

同样接口事件也支持事件之间的继承。

接口事件拥有更好的约束，只要完成实现接口，就可以通过 IDE 的代码生成少写很多代码，其灵感受 CorgiEngine、TopDownEngine 启发。

## 非 MonoBehavior 脚本如何自动销毁

```csharp
public class NoneMonoScript : IUnRegisterList
{
    public List<IUnRegister> UnregisterList { get; } = new List<IUnRegister>();


    void Start()
    {
        TypeEventSystem.Global.Register<EasyEventExample.EventA>(a =>
        {
                    
        }).AddToUnregisterList(this);
    }

    void OnDestroy()
    {
        this.UnRegisterAll();
    }
}
```


## 小结
如果想手动注销，必须要创建一个用于接收事件的方法。

而用自动注销则直接用委托即可。

这两个各有优劣，按需使用。

另外，事件的定义最好使用 struct，因为 struct 的 gc 更少，可以获得更好的性能。

接口事件拥有更好的约束，也可以通过 IDE 的代码生成来提高开发效率。

总之 TypeEventSystem 是一个非常强大的事件工具。

## 更多内容

*   转载请注明地址：[liangxiegame.com](https://liangxiegame.com) （首发） 微信公众号：凉鞋的笔记
*   QFramework 主页：[qframework.cn](https://qframework.cn)
*   QFramework 交流群: 623597263
*   QFramework Github 地址: [https://github.com/liangxiegame/qframework](https://github.com/liangxiegame/qframework)
*   QFramework Gitee 地址：[https://gitee.com/liangxiegame/QFramework](https://gitee.com/liangxiegame/QFramework)
*   GamePix 独立游戏学院 & Unity 进阶小班地址：[https://www.gamepixedu.com/](https://www.gamepixedu.com/)