From 56769cbf0172707e6068d5c16225df65347096f1 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:33:11 +0800 Subject: [PATCH] =?UTF-8?q?feat(architecture):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=BC=82=E6=AD=A5=E9=94=80=E6=AF=81=E5=8A=9F=E8=83=BD=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 Architecture 中添加对 IAsyncDestroyable 接口的支持 - 将销毁集合类型从 IDestroyable 改为 object 以支持多种销毁接口 - 实现 DestroyAsync 方法提供异步销毁能力 - 保留旧的同步 Destroy 方法用于向后兼容 - 在 StateMachineSystem 中添加异步销毁状态的支持 - 添加 IAsyncDestroyable、IAsyncInitializable 和 IAsyncLifecycle 接口定义 - 更新测试代码以使用新的异步销毁方法 - 在架构销毁时清理依赖注入容器 --- .../architecture/IArchitecture.cs | 1 + .../lifecycle/IAsyncDestroyable.cs | 13 +++++ .../IAsyncInitializable.cs | 2 +- .../lifecycle/IAsyncLifecycle.cs | 8 +++ GFramework.Core.Tests/model/AsyncTestModel.cs | 2 +- .../state/StateMachineSystemTests.cs | 6 +-- .../system/AsyncTestSystem.cs | 1 + .../tests/ArchitectureTestsBase.cs | 7 ++- .../tests/AsyncArchitectureTests.cs | 2 +- .../tests/SyncArchitectureTests.cs | 4 +- GFramework.Core/architecture/Architecture.cs | 53 +++++++++++++------ .../state/AsyncContextAwareStateBase.cs | 17 ++++-- GFramework.Core/state/StateMachineSystem.cs | 25 +++++++-- 13 files changed, 109 insertions(+), 32 deletions(-) create mode 100644 GFramework.Core.Abstractions/lifecycle/IAsyncDestroyable.cs rename GFramework.Core.Abstractions/{architecture => lifecycle}/IAsyncInitializable.cs (86%) create mode 100644 GFramework.Core.Abstractions/lifecycle/IAsyncLifecycle.cs diff --git a/GFramework.Core.Abstractions/architecture/IArchitecture.cs b/GFramework.Core.Abstractions/architecture/IArchitecture.cs index e5575a9..d191b54 100644 --- a/GFramework.Core.Abstractions/architecture/IArchitecture.cs +++ b/GFramework.Core.Abstractions/architecture/IArchitecture.cs @@ -1,3 +1,4 @@ +using GFramework.Core.Abstractions.lifecycle; using GFramework.Core.Abstractions.model; using GFramework.Core.Abstractions.system; using GFramework.Core.Abstractions.utility; diff --git a/GFramework.Core.Abstractions/lifecycle/IAsyncDestroyable.cs b/GFramework.Core.Abstractions/lifecycle/IAsyncDestroyable.cs new file mode 100644 index 0000000..73ee300 --- /dev/null +++ b/GFramework.Core.Abstractions/lifecycle/IAsyncDestroyable.cs @@ -0,0 +1,13 @@ +namespace GFramework.Core.Abstractions.lifecycle; + +/// +/// 定义异步销毁接口,用于需要异步清理资源的组件 +/// +public interface IAsyncDestroyable +{ + /// + /// 异步销毁方法,在组件关闭时调用 + /// + /// 表示异步销毁操作的任务 + ValueTask DestroyAsync(); +} \ No newline at end of file diff --git a/GFramework.Core.Abstractions/architecture/IAsyncInitializable.cs b/GFramework.Core.Abstractions/lifecycle/IAsyncInitializable.cs similarity index 86% rename from GFramework.Core.Abstractions/architecture/IAsyncInitializable.cs rename to GFramework.Core.Abstractions/lifecycle/IAsyncInitializable.cs index 49b6cf3..4236768 100644 --- a/GFramework.Core.Abstractions/architecture/IAsyncInitializable.cs +++ b/GFramework.Core.Abstractions/lifecycle/IAsyncInitializable.cs @@ -1,4 +1,4 @@ -namespace GFramework.Core.Abstractions.architecture; +namespace GFramework.Core.Abstractions.lifecycle; /// /// 定义异步初始化接口,用于需要异步初始化的组件或服务 diff --git a/GFramework.Core.Abstractions/lifecycle/IAsyncLifecycle.cs b/GFramework.Core.Abstractions/lifecycle/IAsyncLifecycle.cs new file mode 100644 index 0000000..d9acc1b --- /dev/null +++ b/GFramework.Core.Abstractions/lifecycle/IAsyncLifecycle.cs @@ -0,0 +1,8 @@ +namespace GFramework.Core.Abstractions.lifecycle; + +/// +/// 定义异步生命周期接口,组合了异步初始化和异步销毁 +/// +public interface IAsyncLifecycle : IAsyncInitializable, IAsyncDestroyable +{ +} \ No newline at end of file diff --git a/GFramework.Core.Tests/model/AsyncTestModel.cs b/GFramework.Core.Tests/model/AsyncTestModel.cs index 700229f..b4f0844 100644 --- a/GFramework.Core.Tests/model/AsyncTestModel.cs +++ b/GFramework.Core.Tests/model/AsyncTestModel.cs @@ -1,5 +1,5 @@ -using GFramework.Core.Abstractions.architecture; using GFramework.Core.Abstractions.enums; +using GFramework.Core.Abstractions.lifecycle; using GFramework.Core.model; namespace GFramework.Core.Tests.model; diff --git a/GFramework.Core.Tests/state/StateMachineSystemTests.cs b/GFramework.Core.Tests/state/StateMachineSystemTests.cs index 479be46..35e6309 100644 --- a/GFramework.Core.Tests/state/StateMachineSystemTests.cs +++ b/GFramework.Core.Tests/state/StateMachineSystemTests.cs @@ -133,12 +133,12 @@ public class StateMachineSystemTests } /// - /// 测试Destroy方法不抛出异常 + /// 测试DestroyAsync方法不抛出异常 /// [Test] - public void Destroy_Should_Not_Throw_Exception() + public async Task DestroyAsync_Should_Not_Throw_Exception() { - Assert.That(() => _stateMachine!.Destroy(), Throws.Nothing); + Assert.That(async () => await _stateMachine!.DestroyAsync(), Throws.Nothing); } /// diff --git a/GFramework.Core.Tests/system/AsyncTestSystem.cs b/GFramework.Core.Tests/system/AsyncTestSystem.cs index a45d671..87e64f0 100644 --- a/GFramework.Core.Tests/system/AsyncTestSystem.cs +++ b/GFramework.Core.Tests/system/AsyncTestSystem.cs @@ -1,5 +1,6 @@ using GFramework.Core.Abstractions.architecture; using GFramework.Core.Abstractions.enums; +using GFramework.Core.Abstractions.lifecycle; using GFramework.Core.Abstractions.system; namespace GFramework.Core.Tests.system; diff --git a/GFramework.Core.Tests/tests/ArchitectureTestsBase.cs b/GFramework.Core.Tests/tests/ArchitectureTestsBase.cs index 08d349c..39d9ede 100644 --- a/GFramework.Core.Tests/tests/ArchitectureTestsBase.cs +++ b/GFramework.Core.Tests/tests/ArchitectureTestsBase.cs @@ -34,11 +34,14 @@ public abstract class ArchitectureTestsBase where TArchitecture : /// 销毁架构实例并清理游戏上下文 /// [TearDown] - public void TearDown() + public async Task TearDown() { try { - Architecture?.Destroy(); + if (Architecture != null) + { + await Architecture.DestroyAsync(); + } } finally { diff --git a/GFramework.Core.Tests/tests/AsyncArchitectureTests.cs b/GFramework.Core.Tests/tests/AsyncArchitectureTests.cs index 85a44c4..e842259 100644 --- a/GFramework.Core.Tests/tests/AsyncArchitectureTests.cs +++ b/GFramework.Core.Tests/tests/AsyncArchitectureTests.cs @@ -110,7 +110,7 @@ public class AsyncArchitectureTests : ArchitectureTestsBase(); Assert.That(system, Is.Null); diff --git a/GFramework.Core.Tests/tests/SyncArchitectureTests.cs b/GFramework.Core.Tests/tests/SyncArchitectureTests.cs index c85142d..332666d 100644 --- a/GFramework.Core.Tests/tests/SyncArchitectureTests.cs +++ b/GFramework.Core.Tests/tests/SyncArchitectureTests.cs @@ -114,10 +114,10 @@ public class SyncArchitectureTests : ArchitectureTestsBase /// 测试架构销毁功能,验证销毁后系统被正确销毁且架构进入销毁阶段 /// [Test] - public void Architecture_Destroy_Should_Destroy_All_Systems_And_Enter_Destroyed() + public async Task Architecture_Destroy_Should_Destroy_All_Systems_And_Enter_Destroyed() { Architecture!.Initialize(); - Architecture.Destroy(); + await Architecture.DestroyAsync(); var system = Architecture.Context.GetSystem(); Assert.That(system!.DestroyCalled, Is.True); diff --git a/GFramework.Core/architecture/Architecture.cs b/GFramework.Core/architecture/Architecture.cs index ee09f14..0e60ee7 100644 --- a/GFramework.Core/architecture/Architecture.cs +++ b/GFramework.Core/architecture/Architecture.cs @@ -114,14 +114,14 @@ public abstract class Architecture( private readonly List _pendingInitializableList = []; /// - /// 可销毁组件的去重集合 + /// 可销毁组件的去重集合(支持 IDestroyable 和 IAsyncDestroyable) /// - private readonly HashSet _disposableSet = []; + private readonly HashSet _disposableSet = []; /// /// 存储所有需要销毁的组件(统一管理,保持注册逆序销毁) /// - private readonly List _disposables = []; + private readonly List _disposables = []; /// /// 生命周期感知对象列表 @@ -260,13 +260,15 @@ public abstract class Architecture( } } - // 处理销毁 - if (component is not IDestroyable disposable) return; - // 原子去重:HashSet.Add 返回 true 表示添加成功(之前不存在) - if (_disposableSet.Add(disposable)) + // 处理销毁(支持 IDestroyable 或 IAsyncDestroyable) + if (component is IDestroyable or IAsyncDestroyable) { - _disposables.Add(disposable); - _logger.Trace($"Registered {component.GetType().Name} for destruction"); + // 原子去重:HashSet.Add 返回 true 表示添加成功(之前不存在) + if (_disposableSet.Add(component)) + { + _disposables.Add(component); + _logger.Trace($"Registered {component.GetType().Name} for destruction"); + } } } @@ -361,9 +363,9 @@ public abstract class Architecture( protected abstract void Init(); /// - /// 销毁架构并清理所有组件资源 + /// 异步销毁架构及所有组件 /// - public virtual void Destroy() + public virtual async ValueTask DestroyAsync() { // 检查当前阶段,如果已经处于销毁或已销毁状态则直接返回 if (CurrentPhase >= ArchitecturePhase.Destroying) @@ -376,32 +378,51 @@ public abstract class Architecture( _logger.Info("Starting architecture destruction"); EnterPhase(ArchitecturePhase.Destroying); - // 销毁所有实现了 IDestroyable 的组件(按注册逆序销毁) + // 销毁所有实现了 IAsyncDestroyable 或 IDestroyable 的组件(按注册逆序销毁) _logger.Info($"Destroying {_disposables.Count} disposable components"); for (var i = _disposables.Count - 1; i >= 0; i--) { - var disposable = _disposables[i]; + var component = _disposables[i]; try { - _logger.Debug($"Destroying component: {disposable.GetType().Name}"); - disposable.Destroy(); + _logger.Debug($"Destroying component: {component.GetType().Name}"); + + // 优先使用异步销毁 + if (component is IAsyncDestroyable asyncDestroyable) + { + await asyncDestroyable.DestroyAsync(); + } + else if (component is IDestroyable destroyable) + { + destroyable.Destroy(); + } } catch (Exception ex) { - _logger.Error($"Error destroying {disposable.GetType().Name}", ex); + _logger.Error($"Error destroying {component.GetType().Name}", ex); // 继续销毁其他组件,不会因为一个组件失败而中断 } } _disposables.Clear(); _disposableSet.Clear(); + Container.Clear(); // 进入已销毁阶段 EnterPhase(ArchitecturePhase.Destroyed); _logger.Info("Architecture destruction completed"); } + /// + /// 销毁架构并清理所有组件资源(同步方法,保留用于向后兼容) + /// + [Obsolete("建议使用 DestroyAsync() 以支持异步清理")] + public virtual void Destroy() + { + DestroyAsync().AsTask().GetAwaiter().GetResult(); + } + #endregion #region Component Registration diff --git a/GFramework.Core/state/AsyncContextAwareStateBase.cs b/GFramework.Core/state/AsyncContextAwareStateBase.cs index b12d250..20b9098 100644 --- a/GFramework.Core/state/AsyncContextAwareStateBase.cs +++ b/GFramework.Core/state/AsyncContextAwareStateBase.cs @@ -21,15 +21,26 @@ namespace GFramework.Core.state; /// /// 上下文感知异步状态基类 /// 提供基础的异步状态管理功能和架构上下文访问能力 -/// 实现了IAsyncState(继承IState)和IContextAware接口 +/// 实现了IAsyncState(继承IState)、IContextAware和IAsyncDestroyable接口 /// -public class AsyncContextAwareStateBase : IAsyncState, IContextAware, IDestroyable +public class AsyncContextAwareStateBase : IAsyncState, IContextAware, IDestroyable, IAsyncDestroyable { /// /// 架构上下文引用,用于访问架构相关的服务和数据 /// private IArchitectureContext? _context; + /// + /// 异步销毁当前状态,释放相关资源 + /// 子类可重写此方法以执行特定的异步清理操作 + /// + public virtual ValueTask DestroyAsync() + { + // 默认实现:调用同步 Destroy() + Destroy(); + return ValueTask.CompletedTask; + } + // ============ IState 同步方法显式实现(隐藏 + 运行时保护) ============ /// @@ -125,7 +136,7 @@ public class AsyncContextAwareStateBase : IAsyncState, IContextAware, IDestroyab } /// - /// 销毁当前状态,释放相关资源 + /// 销毁当前状态,释放相关资源(同步方法,保留用于向后兼容) /// 子类可重写此方法以执行特定的清理操作 /// public virtual void Destroy() diff --git a/GFramework.Core/state/StateMachineSystem.cs b/GFramework.Core/state/StateMachineSystem.cs index b94d552..fe853ca 100644 --- a/GFramework.Core/state/StateMachineSystem.cs +++ b/GFramework.Core/state/StateMachineSystem.cs @@ -54,16 +54,25 @@ public class StateMachineSystem : StateMachine, IStateMachineSystem } /// - /// 销毁方法,在系统关闭时调用 + /// 销毁方法,在系统关闭时调用(同步方法,保留用于向后兼容) /// + [Obsolete("建议使用 DestroyAsync() 以支持异步清理")] public virtual void Destroy() + { + DestroyAsync().AsTask().GetAwaiter().GetResult(); + } + + /// + /// 异步销毁方法,在系统关闭时调用 + /// + public virtual async ValueTask DestroyAsync() { // 退出当前状态 if (Current != null) { if (Current is IAsyncState asyncState) { - asyncState.OnExitAsync(null); + await asyncState.OnExitAsync(null); // ✅ 正确等待异步清理 } else { @@ -74,7 +83,17 @@ public class StateMachineSystem : StateMachine, IStateMachineSystem } // 清理所有状态 - foreach (var state in States.Values.OfType()) state.Destroy(); + foreach (var state in States.Values) + { + if (state is IAsyncDestroyable asyncDestroyable) + { + await asyncDestroyable.DestroyAsync(); + } + else if (state is IDestroyable destroyable) + { + destroyable.Destroy(); + } + } States.Clear(); }