Unity C# 消息机制-填坑笔记 (2)

一、前言

笔者曾在高中时写过一篇文风浮夸的文章(点我跳转),虽然发布在2021年,但是它的诞生时间更早(大概2020),只不过中途进了回收站,转眼笔者已经大一了,就想写一个属于自己的初步游戏框架(进阶工具集),其中最重要的一部分就是消息驱动。本文需要一定的编程基础。
在这里插入图片描述
另外本文不会讲很多内容,仅仅是作为高一时那篇文章的填坑笔记,简单讨论一下怎么设计一个比较好的消息机制。

二、填坑秘籍

第一个坑:泛型太多难维护

当然还是跟上篇文章非常类似,主要是为了那篇文章的坑。
那篇文章里说到Register和Remove,Invoke的时候只给出了无参数的实现,然后我给出的后续实现是通过写一大堆泛型来补充参数。

void Register<T,K,A,V>(T a,K b, A c,V d);
void Register<T,K,A>(T a,K b, A c);
void Register<T,K>(T a,K b);
void Register<T>(T a);
void Register();

这样的函数要写多个重载,代码很难维护…但是性能非常好
当然读者可能在网上看到这种实现

void Register(params object[] parm); 
//void Register(params dynamic[] parm);  也是object实现的有装箱
void MyMethod()
{
    
    
	Register(1,"str");
}

这种实现最大的问题就是在值类型(栈空间)到object(堆空间)的装箱过程,性能瓶颈,但是代码极容易维护。

我无意间想起C# 提供了一种新的数据类型,Tuple/ValueTuple(元组)

void Register(ValueTuple tuple); 

void MyMethod()
{
    
    
	Register((10,"30"));
}

这样可以避免装箱问题,但是要求用户注册的委托只能带有ValueTuple类型的唯一参数然后自己处理元组类型转换,一定程度上有些侵入性(对用户有强制性),但是代码变得容易维护且兼顾性能。

如果你不能很好的理解这些内容,请尝试自己实现上篇文章的消息机制。
至于选择什么,还要看具体情景,没有最好的设计,只有最合适。

第二个坑:选什么当key

上篇文章我们只提到了三种选择,如下

1.string - 描述性极强,容易引发GC (string来回拷贝)
2.enum - 兼顾描述性和性能但不是很方便(手动增加枚举)
3.int/long - 不具备描述性 (不知道int对应什么事件)

虽然心里一百个不愿意用int,但是很多公司确实是这样做的,但是会建立工具自动生成并绑定int和一些描述性的值
后来受到启发,我发现任意类型都可以作为key,如下

1.object - 较为松散,容易引发装箱,通过C#的拓展方法可以实现object.Send()这样的快乐API
2. interface - 可以要求用户仅使用实现接口的类作为key,也有object的优点

可能读完这段内容难以理解,简单概括上篇文章的Dictionary < TKey,Delegate > 中的Key可以是任意类型,不一定非要局限在一些特殊类型。

interface IMessage{
    
    }
class MyMessage:IMessage
{
    
    
	public int id = 10;
}
class AObj
{
    
    
	void OnMyMessage(MyMessage message)
	{
    
    
		//处理消息
	}
	
	void MyMethod()
	{
    
    
		Register<MyMessage>(OnMyMessage);
		Send<MyMessage>(new MyMessage{
    
    id = 20});
	}
}

这些内容笔者因为还在上学没有时间统一整理,只能简单对读者进行启发,更多还是要靠自己探索。建议读者康康Github上的这些优秀项目的相关实现

MediatR
IFramework

下一篇文章:基于观察者模式的全局消息机制中,笔者将会介绍使用观察者模式实现消息机制
在这里插入图片描述

猜你喜欢

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