原本的 QFramework 在架构设计上没有维护全局唯一事件字典(因为运行过程中至少存在三个事件字典),删除冗余的 EasyEvents 类,调整TypeEventSystem为静态类,移除 Global 字段,直接使用类名获取全局唯一静态字典,项目过程中维护TypeEventSystem类的全局唯一静态字典,此修改会导致Example中的 Global 无效,为了维持原本的 QF 使用习惯,可选不移除 Global 变量。
EasyEvents 和 TypeEventSystem 疑点或问题点
为什么 TypeEventSystem 内部要 new 一个 EasyEvents 对象 ?
public class TypeEventSystem
{
// 这是 TypeEventSystem 静态实例 Global
public static readonly TypeEventSystem Global = new();
// 这里却 new 了一个 EasyEvents
readonly EasyEvents _easyEvents = new();
}
TypeEventSystem 类中创建了一个静态实例对象 Global ,代表在整个程序运行中只会存在一个静态实例对象 Global ,而 Global 这个静态实例对象 new 的过程中会生成一个只读 EasyEvents 实例对象,可以表示为 TypeEventSystem.Global._easyEvents
[!CAUTION]
在 Architecture 抽象类中,同时 new 了一个 TypeEventSystem 类对象,对象名为: _typeEventSystem
public void Send<T>() where T : new()
{
_easyEvents.GetEvent<EasyEvent<T>>()?.Trigger(new T());
}
public void Send<T>(T e)
{
_easyEvents.GetEvent<EasyEvent<T>>()?.Trigger(e);
}
/// <summary>
/// 默认注册带一个参数的委托
/// </summary>
/// <remarks>注册时执行 GetOrAddEvent ,如果存在就注册给具体 EasyEvent 实例对象,不存在则创建一个新的并添加到 EasyEvents 的字典</remarks>
/// <returns></returns>
public IUnRegister Register<T>(Action<T> onEvent) =>
_easyEvents.GetOrAddEvent<EasyEvent<T>>().Register(onEvent);
public void UnRegister<T>(Action<T> onEvent)
{
EasyEvent<T> e = _easyEvents.GetEvent<EasyEvent<T>>();
e?.UnRegister(onEvent);
}
EasyEvents
// 获取指定类型的全局事件实例
public static T Get<T>() where T : IEasyEvent => GlobalEasyEvents.GetEvent<T>();
// 注册指定类型的事件
public static void Register<T>() where T : IEasyEvent, new()
{
GlobalEasyEvents.AddEvent<T>();
}
// 添加指定类型的事件实例到字典中
public void AddEvent<T>() where T : IEasyEvent, new()
{
_typeEventDictionary.Add(typeof(T), new T());
}
// 获取指定类型的事件实例
public T GetEvent<T>() where T : IEasyEvent => _typeEventDictionary.TryGetValue(typeof(T), out var e) ? (T)e : default;
// 获取或添加指定类型的事件实例
public T GetOrAddEvent<T>() where T : IEasyEvent, new()
{
var eType = typeof(T);
if (_typeEventDictionary.TryGetValue(eType, out var e)) return (T)e;
var t = new T();
_typeEventDictionary.Add(eType, t);
return t;
}
#region 新版
static readonly Dictionary<Type, IEasyEvent> TypeEventDictionary = new();
static T GetOrAddEvent<T>() where T : IEasyEvent, new()
{
var eType = typeof(T);
if (TypeEventDictionary.TryGetValue(eType, out var e)) return (T)e;
var t = new T();
TypeEventDictionary.Add(eType, t);
return t;
}
static T GetEvent<T>() where T : IEasyEvent =>
TypeEventDictionary.TryGetValue(typeof(T), out var e) ? (T)e : default;
public static void Send<T>() where T : new()
{
GetEvent<EasyEvent<T>>()?.Trigger(new T());
}
public static void Send<T>(T e)
{
GetEvent<EasyEvent<T>>()?.Trigger(e);
}
public static IUnRegister Register<T>(Action<T> onEvent) =>
GetOrAddEvent<EasyEvent<T>>().Register(onEvent);
public static void UnRegister<T>(Action<T> onEvent)
{
EasyEvent<T> e = GetEvent<EasyEvent<T>>();
e?.UnRegister(onEvent);
}
#endregion
Architecture
#region 新版
public void SendEvent<TEvent>() where TEvent : new()
{
TypeEventSystem.Send<TEvent>();
}
public void SendEvent<TEvent>(TEvent e)
{
TypeEventSystem.Send(e);
}
public IUnRegister RegisterEvent<TEvent>(Action<TEvent> onEvent) => TypeEventSystem.Register(onEvent);
public void UnRegisterEvent<TEvent>(Action<TEvent> onEvent)
{
TypeEventSystem.UnRegister(onEvent);
}
#endregion
原本的 QFramework 在架构设计上没有维护全局唯一事件字典(因为运行过程中至少存在三个事件字典),删除冗余的 EasyEvents 类,调整TypeEventSystem为静态类,移除 Global 字段,直接使用类名获取全局唯一静态字典,项目过程中维护TypeEventSystem类的全局唯一静态字典,此修改会导致Example中的 Global 无效,为了维持原本的 QF 使用习惯,可选不移除 Global 变量。
EasyEvents 和 TypeEventSystem 疑点或问题点
为什么 TypeEventSystem 内部要 new 一个 EasyEvents 对象 ?
TypeEventSystem
类中创建了一个静态实例对象Global
,代表在整个程序运行中只会存在一个静态实例对象Global
,而Global
这个静态实例对象new
的过程中会生成一个只读EasyEvents
实例对象,可以表示为TypeEventSystem.Global._easyEvents
根据以上可以得知,到目前为止,当程序运行,且使用了架构时,内存中实际会存在两个
EasyEvents
类型的实例对象,这两个实例对象是相互独立的。现在再来看
EasyEvents
类它也创造了一个全局静态实例对象,
GlobalEasyEvents
,可以表示为EasyEvents.GlobalEasyEvents
现在可以得知:当程序运行,且使用了架构时,内存中至少有三个
EasyEvents
实例对象,其中一个静态对象,两个非静态对象EasyEvents.GlobalEasyEvents
:全局静态对象TypeEventSystem.Global._easyEvents
:全局静态 TypeEventSystem 对象中的非静态成员变量_typeEventSystem._easyEvents
:_typeEventSystem
实例对象中的非静态成员变量然后又可以看到
EasyEvents
类中存在一个非静态的事件字典,那么代表了内存中一共包含三个_typeEventDictionary
字典,因为每次对象生成时都会生成一份非静态的字典现在重要的问题点在于
TypeEventSystem
的公共方法和EasyEvents
的公共方法TypeEventSystem
EasyEvents
首先我们走一遍 注册方法 的路径
Register
是公共非静态方法,通常是使用TypeEventSystem.Global
TypeEventSystem.Global.Register
TypeEventSystem.Global._easyEvents
TypeEventSystem.Global._easyEvents.GetOrAddEvent
TypeEventSystem.Global._easyEvents._typeEventDictionary
TypeEventSystem.Global._easyEvents._typeEventDictionary.Add
这里添加IEasyEvent
对象到字典中可以很明显看到使用的是
TypeEventSystem.Global
内部的非静态字段,也就是说,通常 QF 维护的字典是TypeEventSystem.Global._easyEvents._typeEventDictionary
,和EasyEvents.GlobalEasyEvents
这个静态对象没有任何关系,但是它依旧存在于内存中,同时也和架构中创建的_typeEventSystem
也没有关系尽管
EasyEvents
类中提供了Register
和Get
两个静态方法,但是很明显,在 Rider 中可以清楚地看到 QF 内部并没有任何时使用到它们的地方总结修改方案
目标: 尽量维持原版 API 的使用方法,删除多余部分,使得结构更加简洁
TypeEventSystem.Global
通常也仅仅是开发初期使用,后期可以完全替换为 QF 的事件规则解决过程
EasyEvents
这个类对于一般用户是无感的,在修改过程中可以完全舍弃,用户也不会感知到和原版的差异EasyEvents
类中的字典成员变量移动到TypeEventSystem
中,并直接设置为只读变量,命名为TypeEventDictionary
,同时移动原本EasyEvents
类中的GetOrAddEvent
方法和GetEvent
方法(当然不移动这两个封装方法也可以,直接将这个两个方法内部实现编写到Register
,Send
,UnRegister
内部,不够优雅hhh),让 QF 的事件系统从真正意义上只维护一个全局静态字典,从架构根本上解决这个问题(之前如果没有意外情况,按规则调用的话,也可以说是全局唯一字典)Global
,由于目前官方推荐的开发初始使用方法中包含有TypeEventSystem.Global
,可能导致原本的教程需要补充修改这一点。Global
,那么可以TypeEventDictionary
设计为静态只读,TypeEventSystem
类直接改为静态类,所有方法均可以改为静态方法,相比于之前,省略了Global
的编写。Global
,那么只需要移动方法即可。但是调用Global
这一步是完全可以省略的。解决方案
TypeEventSystem
Architecture
删除
Architecture
中的readonly TypeEventSystem _typeEventSystem = new();
删除
EasyEvents
类