feat(state): 实现异步状态基类的同步方法限制

- 为 AsyncContextAwareStateBase 添加同步方法异常抛出机制
- 禁止在异步状态中使用 OnEnter、OnExit 和 CanTransitionTo 同步方法
- 提供清晰的错误提示引导使用对应的异步方法
- 修复 StateMachine 中的状态转换逻辑确保线程安全
- 更新 IAsyncState 接口继承 IState 接口统一状态管理
This commit is contained in:
GeWuYou 2026-02-15 20:45:24 +08:00 committed by gewuyou
parent 38967d047a
commit 22c1d08dc3
3 changed files with 40 additions and 4 deletions

View File

@ -16,7 +16,7 @@ namespace GFramework.Core.Abstractions.state;
/// <summary>
/// 异步状态机状态接口,定义了状态的异步行为和转换规则
/// </summary>
public interface IAsyncState
public interface IAsyncState : IState
{
/// <summary>
/// 当状态被激活进入时异步调用

View File

@ -61,6 +61,39 @@ public class AsyncContextAwareStateBase : IAsyncState, IContextAware, IDisposabl
return Task.FromResult(true);
}
/// <summary>
/// 同步进入状态(不推荐使用)
/// 异步状态应该使用 OnEnterAsync 方法
/// </summary>
/// <exception cref="NotSupportedException">异步状态不支持同步操作</exception>
public virtual void OnEnter(IState? from)
{
throw new NotSupportedException(
$"This is an async state ({GetType().Name}). Use OnEnterAsync instead of OnEnter.");
}
/// <summary>
/// 同步退出状态(不推荐使用)
/// 异步状态应该使用 OnExitAsync 方法
/// </summary>
/// <exception cref="NotSupportedException">异步状态不支持同步操作</exception>
public virtual void OnExit(IState? to)
{
throw new NotSupportedException(
$"This is an async state ({GetType().Name}). Use OnExitAsync instead of OnExit.");
}
/// <summary>
/// 同步判断是否可以转换(不推荐使用)
/// 异步状态应该使用 CanTransitionToAsync 方法
/// </summary>
/// <exception cref="NotSupportedException">异步状态不支持同步操作</exception>
public virtual bool CanTransitionTo(IState target)
{
throw new NotSupportedException(
$"This is an async state ({GetType().Name}). Use CanTransitionToAsync instead of CanTransitionTo.");
}
/// <summary>
/// 设置架构上下文
/// </summary>

View File

@ -138,20 +138,23 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
public async Task<bool> ChangeToAsync<T>() where T : IState
{
IState target;
IState? currentSnapshot;
lock (_lock)
{
if (!States.TryGetValue(typeof(T), out target!))
throw new InvalidOperationException($"State {typeof(T).Name} not registered.");
currentSnapshot = Current; // 在锁内获取当前状态的快照
}
// 验证转换(在锁外执行异步操作)
if (Current != null)
if (currentSnapshot != null)
{
var canTransition = await CanTransitionToAsync(Current, target);
var canTransition = await CanTransitionToAsync(currentSnapshot, target);
if (!canTransition)
{
await OnTransitionRejectedAsync(Current, target);
await OnTransitionRejectedAsync(currentSnapshot, target);
return false;
}
}