feat(architecture): 添加异步销毁功能支持

- 在 Architecture 中添加对 IAsyncDestroyable 接口的支持
- 将销毁集合类型从 IDestroyable 改为 object 以支持多种销毁接口
- 实现 DestroyAsync 方法提供异步销毁能力
- 保留旧的同步 Destroy 方法用于向后兼容
- 在 StateMachineSystem 中添加异步销毁状态的支持
- 添加 IAsyncDestroyable、IAsyncInitializable 和 IAsyncLifecycle 接口定义
- 更新测试代码以使用新的异步销毁方法
- 在架构销毁时清理依赖注入容器
This commit is contained in:
GeWuYou 2026-02-17 18:33:11 +08:00 committed by gewuyou
parent 73d1fcf6fd
commit 56769cbf01
13 changed files with 109 additions and 32 deletions

View File

@ -1,3 +1,4 @@
using GFramework.Core.Abstractions.lifecycle;
using GFramework.Core.Abstractions.model; using GFramework.Core.Abstractions.model;
using GFramework.Core.Abstractions.system; using GFramework.Core.Abstractions.system;
using GFramework.Core.Abstractions.utility; using GFramework.Core.Abstractions.utility;

View File

@ -0,0 +1,13 @@
namespace GFramework.Core.Abstractions.lifecycle;
/// <summary>
/// 定义异步销毁接口,用于需要异步清理资源的组件
/// </summary>
public interface IAsyncDestroyable
{
/// <summary>
/// 异步销毁方法,在组件关闭时调用
/// </summary>
/// <returns>表示异步销毁操作的任务</returns>
ValueTask DestroyAsync();
}

View File

@ -1,4 +1,4 @@
namespace GFramework.Core.Abstractions.architecture; namespace GFramework.Core.Abstractions.lifecycle;
/// <summary> /// <summary>
/// 定义异步初始化接口,用于需要异步初始化的组件或服务 /// 定义异步初始化接口,用于需要异步初始化的组件或服务

View File

@ -0,0 +1,8 @@
namespace GFramework.Core.Abstractions.lifecycle;
/// <summary>
/// 定义异步生命周期接口,组合了异步初始化和异步销毁
/// </summary>
public interface IAsyncLifecycle : IAsyncInitializable, IAsyncDestroyable
{
}

View File

@ -1,5 +1,5 @@
using GFramework.Core.Abstractions.architecture;
using GFramework.Core.Abstractions.enums; using GFramework.Core.Abstractions.enums;
using GFramework.Core.Abstractions.lifecycle;
using GFramework.Core.model; using GFramework.Core.model;
namespace GFramework.Core.Tests.model; namespace GFramework.Core.Tests.model;

View File

@ -133,12 +133,12 @@ public class StateMachineSystemTests
} }
/// <summary> /// <summary>
/// 测试Destroy方法不抛出异常 /// 测试DestroyAsync方法不抛出异常
/// </summary> /// </summary>
[Test] [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);
} }
/// <summary> /// <summary>

View File

@ -1,5 +1,6 @@
using GFramework.Core.Abstractions.architecture; using GFramework.Core.Abstractions.architecture;
using GFramework.Core.Abstractions.enums; using GFramework.Core.Abstractions.enums;
using GFramework.Core.Abstractions.lifecycle;
using GFramework.Core.Abstractions.system; using GFramework.Core.Abstractions.system;
namespace GFramework.Core.Tests.system; namespace GFramework.Core.Tests.system;

View File

@ -34,11 +34,14 @@ public abstract class ArchitectureTestsBase<TArchitecture> where TArchitecture :
/// 销毁架构实例并清理游戏上下文 /// 销毁架构实例并清理游戏上下文
/// </summary> /// </summary>
[TearDown] [TearDown]
public void TearDown() public async Task TearDown()
{ {
try try
{ {
Architecture?.Destroy(); if (Architecture != null)
{
await Architecture.DestroyAsync();
}
} }
finally finally
{ {

View File

@ -110,7 +110,7 @@ public class AsyncArchitectureTests : ArchitectureTestsBase<AsyncTestArchitectur
public async Task Architecture_Destroy_Should_Destroy_All_Systems() public async Task Architecture_Destroy_Should_Destroy_All_Systems()
{ {
await Architecture!.InitializeAsync(); await Architecture!.InitializeAsync();
Architecture.Destroy(); await Architecture.DestroyAsync();
var system = Architecture.Context.GetSystem<TestSystem>(); var system = Architecture.Context.GetSystem<TestSystem>();
Assert.That(system, Is.Null); Assert.That(system, Is.Null);

View File

@ -114,10 +114,10 @@ public class SyncArchitectureTests : ArchitectureTestsBase<SyncTestArchitecture>
/// 测试架构销毁功能,验证销毁后系统被正确销毁且架构进入销毁阶段 /// 测试架构销毁功能,验证销毁后系统被正确销毁且架构进入销毁阶段
/// </summary> /// </summary>
[Test] [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!.Initialize();
Architecture.Destroy(); await Architecture.DestroyAsync();
var system = Architecture.Context.GetSystem<TestSystem>(); var system = Architecture.Context.GetSystem<TestSystem>();
Assert.That(system!.DestroyCalled, Is.True); Assert.That(system!.DestroyCalled, Is.True);

View File

@ -114,14 +114,14 @@ public abstract class Architecture(
private readonly List<IInitializable> _pendingInitializableList = []; private readonly List<IInitializable> _pendingInitializableList = [];
/// <summary> /// <summary>
/// 可销毁组件的去重集合 /// 可销毁组件的去重集合(支持 IDestroyable 和 IAsyncDestroyable
/// </summary> /// </summary>
private readonly HashSet<IDestroyable> _disposableSet = []; private readonly HashSet<object> _disposableSet = [];
/// <summary> /// <summary>
/// 存储所有需要销毁的组件(统一管理,保持注册逆序销毁) /// 存储所有需要销毁的组件(统一管理,保持注册逆序销毁)
/// </summary> /// </summary>
private readonly List<IDestroyable> _disposables = []; private readonly List<object> _disposables = [];
/// <summary> /// <summary>
/// 生命周期感知对象列表 /// 生命周期感知对象列表
@ -260,13 +260,15 @@ public abstract class Architecture(
} }
} }
// 处理销毁 // 处理销毁(支持 IDestroyable 或 IAsyncDestroyable
if (component is not IDestroyable disposable) return; if (component is IDestroyable or IAsyncDestroyable)
// 原子去重HashSet.Add 返回 true 表示添加成功(之前不存在)
if (_disposableSet.Add(disposable))
{ {
_disposables.Add(disposable); // 原子去重HashSet.Add 返回 true 表示添加成功(之前不存在)
_logger.Trace($"Registered {component.GetType().Name} for destruction"); 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(); protected abstract void Init();
/// <summary> /// <summary>
/// 销毁架构并清理所有组件资源 /// 异步销毁架构及所有组件
/// </summary> /// </summary>
public virtual void Destroy() public virtual async ValueTask DestroyAsync()
{ {
// 检查当前阶段,如果已经处于销毁或已销毁状态则直接返回 // 检查当前阶段,如果已经处于销毁或已销毁状态则直接返回
if (CurrentPhase >= ArchitecturePhase.Destroying) if (CurrentPhase >= ArchitecturePhase.Destroying)
@ -376,32 +378,51 @@ public abstract class Architecture(
_logger.Info("Starting architecture destruction"); _logger.Info("Starting architecture destruction");
EnterPhase(ArchitecturePhase.Destroying); EnterPhase(ArchitecturePhase.Destroying);
// 销毁所有实现了 IDestroyable 的组件(按注册逆序销毁) // 销毁所有实现了 IAsyncDestroyable 或 IDestroyable 的组件(按注册逆序销毁)
_logger.Info($"Destroying {_disposables.Count} disposable components"); _logger.Info($"Destroying {_disposables.Count} disposable components");
for (var i = _disposables.Count - 1; i >= 0; i--) for (var i = _disposables.Count - 1; i >= 0; i--)
{ {
var disposable = _disposables[i]; var component = _disposables[i];
try try
{ {
_logger.Debug($"Destroying component: {disposable.GetType().Name}"); _logger.Debug($"Destroying component: {component.GetType().Name}");
disposable.Destroy();
// 优先使用异步销毁
if (component is IAsyncDestroyable asyncDestroyable)
{
await asyncDestroyable.DestroyAsync();
}
else if (component is IDestroyable destroyable)
{
destroyable.Destroy();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error($"Error destroying {disposable.GetType().Name}", ex); _logger.Error($"Error destroying {component.GetType().Name}", ex);
// 继续销毁其他组件,不会因为一个组件失败而中断 // 继续销毁其他组件,不会因为一个组件失败而中断
} }
} }
_disposables.Clear(); _disposables.Clear();
_disposableSet.Clear(); _disposableSet.Clear();
Container.Clear();
// 进入已销毁阶段 // 进入已销毁阶段
EnterPhase(ArchitecturePhase.Destroyed); EnterPhase(ArchitecturePhase.Destroyed);
_logger.Info("Architecture destruction completed"); _logger.Info("Architecture destruction completed");
} }
/// <summary>
/// 销毁架构并清理所有组件资源(同步方法,保留用于向后兼容)
/// </summary>
[Obsolete("建议使用 DestroyAsync() 以支持异步清理")]
public virtual void Destroy()
{
DestroyAsync().AsTask().GetAwaiter().GetResult();
}
#endregion #endregion
#region Component Registration #region Component Registration

View File

@ -21,15 +21,26 @@ namespace GFramework.Core.state;
/// <summary> /// <summary>
/// 上下文感知异步状态基类 /// 上下文感知异步状态基类
/// 提供基础的异步状态管理功能和架构上下文访问能力 /// 提供基础的异步状态管理功能和架构上下文访问能力
/// 实现了IAsyncState继承IState和IContextAware接口 /// 实现了IAsyncState继承IState、IContextAware和IAsyncDestroyable接口
/// </summary> /// </summary>
public class AsyncContextAwareStateBase : IAsyncState, IContextAware, IDestroyable public class AsyncContextAwareStateBase : IAsyncState, IContextAware, IDestroyable, IAsyncDestroyable
{ {
/// <summary> /// <summary>
/// 架构上下文引用,用于访问架构相关的服务和数据 /// 架构上下文引用,用于访问架构相关的服务和数据
/// </summary> /// </summary>
private IArchitectureContext? _context; private IArchitectureContext? _context;
/// <summary>
/// 异步销毁当前状态,释放相关资源
/// 子类可重写此方法以执行特定的异步清理操作
/// </summary>
public virtual ValueTask DestroyAsync()
{
// 默认实现:调用同步 Destroy()
Destroy();
return ValueTask.CompletedTask;
}
// ============ IState 同步方法显式实现(隐藏 + 运行时保护) ============ // ============ IState 同步方法显式实现(隐藏 + 运行时保护) ============
/// <summary> /// <summary>
@ -125,7 +136,7 @@ public class AsyncContextAwareStateBase : IAsyncState, IContextAware, IDestroyab
} }
/// <summary> /// <summary>
/// 销毁当前状态,释放相关资源 /// 销毁当前状态,释放相关资源(同步方法,保留用于向后兼容)
/// 子类可重写此方法以执行特定的清理操作 /// 子类可重写此方法以执行特定的清理操作
/// </summary> /// </summary>
public virtual void Destroy() public virtual void Destroy()

View File

@ -54,16 +54,25 @@ public class StateMachineSystem : StateMachine, IStateMachineSystem
} }
/// <summary> /// <summary>
/// 销毁方法,在系统关闭时调用 /// 销毁方法,在系统关闭时调用(同步方法,保留用于向后兼容)
/// </summary> /// </summary>
[Obsolete("建议使用 DestroyAsync() 以支持异步清理")]
public virtual void Destroy() public virtual void Destroy()
{
DestroyAsync().AsTask().GetAwaiter().GetResult();
}
/// <summary>
/// 异步销毁方法,在系统关闭时调用
/// </summary>
public virtual async ValueTask DestroyAsync()
{ {
// 退出当前状态 // 退出当前状态
if (Current != null) if (Current != null)
{ {
if (Current is IAsyncState asyncState) if (Current is IAsyncState asyncState)
{ {
asyncState.OnExitAsync(null); await asyncState.OnExitAsync(null); // ✅ 正确等待异步清理
} }
else else
{ {
@ -74,7 +83,17 @@ public class StateMachineSystem : StateMachine, IStateMachineSystem
} }
// 清理所有状态 // 清理所有状态
foreach (var state in States.Values.OfType<IDestroyable>()) 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(); States.Clear();
} }