Unity3D C# 基于协变、观察者、unsafe转换的事件系统实战

项目地址-CoEvent

在这里插入图片描述

CoEvent

CoEvent是一个能约束参数类型的,能约束调用类型的,参数和调用类型安全的轻量级本地消息系统,支持一切能支持Unsafe.As类似API的CSharp编程平台。

目前了解的支持平台有.NET CORE和Unity3D 2020.1 OR NEWER。

理论上版本更低的Unity3D也能实现(可能在后续版本提供支持),不过没有提供原生的UnsafeUtility.As,可以自己实现一个替换上去。

一、优势

CoEvent 的优势主要在于“约束” ,现在传统的消息系统一般有如下方式实现

  • 1.反射(Unity的SendMessage已经被无情抛弃了)
  • 2.int,string,enum做消息标识(注册和取消要手动写一大串泛型参数,调用要手动写泛型参数,如果写错了…后果不堪设想)
  • 3.接口化的,基类化的(部分类似的基于观察者模式写了接口,继承基类可以比较容易实现这种约束,但是继承接口的很难去做约束,不好判断消息类型,很多接口约束只能有唯一消息)

给大家看看主流实现的方式怎么调用和实现的

//Unity原生SendMessage,通过反射,效率低,容易写错名字,写错时候字符串是没提示的,很难查错
Monobehaviour.SendMessage("Ttt");
//int,string,enum做标识的
EventCenter.Add<int,int>("name",MyAction);//在注册时需要写泛型
EventCenter.Send("name",10,20);  //调用时没有约束,我也可以传入错误的参数类型,当写多了就变成了灾难。
//基类和接口继承的
//基类不用说了,侵入性太强了
//接口继承的,一般一个类只能有一个事件,不然很难判断类型的参数
//当然也有写分析器的,那都是大牛,QAQ,本渣做不到

而CoEvent是怎么实现的?
CoEvent采用了第二种方式,但是不同的是消息标识是接口,很巧妙的利用协变实现了约束.

CoEvent能根据泛型推断省略注册和取消时的泛型参数,也能限制发布事件时的参数类型。

也就是说,CoEvent是不会发生那种写错泛型参数的类型情况的,也不会发生Send注册,结果Call调用这种情况。

极大的降低了开发者的代码失误几率,减少了Debug的时间。

二、使用

CoEvent本着简单易用的原则实现了基于观察者模式的一个事件系统。能很轻松实现跨对象,跨模块之间的事件通信。

1.前期配置:

如果你是在Unity3D 2020.1以上使用,无需配置任何内容。
如果你是在.NetCore使用,需要在任意一个参与编译的文件里加上宏定义,#define NETCORE
如果你在其他平台使用,可以在CoUnsafeAs.cs里去给出Unsafe.As的类似实现。
无法实现?不支持该平台QAQ

2.事件定义

//通用事件,可以Send可以Call,但是只能用一个!!!
public interface MyEvent: IGenericEvent<参数类型,参数类型...>
//可发送
public interface MyEvent: ISendEvent<...>
//可调用(最后一个泛型参数是返回值)
public interface MyEvent: ICallEvent<...>

3.注册和取消事件(MyAction也是被约束类型的)

this.Operator<消息类型接口>().Subcribe(MyAction);
this.Operator<消息类型接口>().UnSubcribe(MyAction);

4.调用和发送

this.Operator<消息类型接口>().Send(...参数们);
var results = this.Operator<消息类型接口>().Call(...参数们);

三、例子

using CoEvent;
using UnityEngine;


public interface IMyTest : ISendEvent<int, int> {
    
     }
public class Test : MonoBehaviour
{
    
    

    void Ttt(int t,int k)
    {
    
    
        Debug.Log($"{
      
      t}:{
      
      k}");
    }

    void Start()
    {
    
    
    	//也无需像其他事件系统一样注册时写明参数的泛型
        this.Operator<IMyTest>().Subscribe(Ttt);
        this.Operator<IMyTest>().UnSubscribe(Ttt);
        //你绝对不会写错参数类型
        this.Operator<IMyTest>().Send(10,100);
    }

}

猜你喜欢

转载自blog.csdn.net/qq_46273241/article/details/130723091