mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-25 13:33:28 +08:00
refactor(state): 优化状态机实现并增强上下文安全检查
- 在 ContextAwareStateBase 和 AsyncContextAwareStateBase 中添加架构上下文空值检查 - 引入 HashSet 用于快速检查状态注册状态,提升性能 - 重构注销逻辑,分离准备和完成阶段的处理 - 优化回退功能,跳过已注销的状态并使用 O(1) 复杂度检查 - 统一状态切换中的进入和退出逻辑处理 - 简化状态转换验证流程,提升代码可读性 - 添加辅助方法处理异步状态操作的统一入口 - [release ci]
This commit is contained in:
parent
a5daadea96
commit
703328deb2
@ -76,7 +76,8 @@ public class AsyncContextAwareStateBase : IAsyncState, IContextAware, IDisposabl
|
|||||||
/// <returns>架构上下文实例</returns>
|
/// <returns>架构上下文实例</returns>
|
||||||
public IArchitectureContext GetContext()
|
public IArchitectureContext GetContext()
|
||||||
{
|
{
|
||||||
return _context!;
|
return _context ?? throw new InvalidOperationException(
|
||||||
|
$"Architecture context has not been set. Call {nameof(SetContext)} before accessing the context.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -32,7 +32,8 @@ public class ContextAwareStateBase : IState, IContextAware, IDisposable
|
|||||||
/// <returns>架构上下文实例</returns>
|
/// <returns>架构上下文实例</returns>
|
||||||
public IArchitectureContext GetContext()
|
public IArchitectureContext GetContext()
|
||||||
{
|
{
|
||||||
return _context!;
|
return _context ?? throw new InvalidOperationException(
|
||||||
|
$"Architecture context has not been set. Call {nameof(SetContext)} before accessing the context.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -9,6 +9,7 @@ namespace GFramework.Core.state;
|
|||||||
public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||||
{
|
{
|
||||||
private readonly object _lock = new();
|
private readonly object _lock = new();
|
||||||
|
private readonly HashSet<IState> _registeredStates = new(); // 优化:用于快速检查状态是否注册
|
||||||
private readonly Stack<IState> _stateHistory = new();
|
private readonly Stack<IState> _stateHistory = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -30,6 +31,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
States[state.GetType()] = state;
|
States[state.GetType()] = state;
|
||||||
|
_registeredStates.Add(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -41,26 +43,17 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <typeparam name="T">要注销的状态类型</typeparam>
|
/// <typeparam name="T">要注销的状态类型</typeparam>
|
||||||
public IStateMachine Unregister<T>() where T : IState
|
public IStateMachine Unregister<T>() where T : IState
|
||||||
{
|
{
|
||||||
lock (_lock)
|
var stateToUnregister = PrepareUnregister<T>(out var isCurrentState);
|
||||||
{
|
if (stateToUnregister == null) return this;
|
||||||
var type = typeof(T);
|
|
||||||
if (!States.TryGetValue(type, out var state)) return this;
|
|
||||||
|
|
||||||
// 如果当前状态是要注销的状态,则先执行退出逻辑
|
// 如果是当前状态,执行同步退出
|
||||||
if (Current == state)
|
if (isCurrentState)
|
||||||
{
|
{
|
||||||
Current.OnExit(null);
|
Current!.OnExit(null);
|
||||||
Current = null;
|
Current = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从历史记录中移除该状态的所有引用
|
CompleteUnregister(stateToUnregister);
|
||||||
var tempStack = new Stack<IState>(_stateHistory.Reverse());
|
|
||||||
_stateHistory.Clear();
|
|
||||||
foreach (var historyState in tempStack.Where(s => s != state)) _stateHistory.Push(historyState);
|
|
||||||
|
|
||||||
States.Remove(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,36 +63,17 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <typeparam name="T">要注销的状态类型</typeparam>
|
/// <typeparam name="T">要注销的状态类型</typeparam>
|
||||||
public async Task<IStateMachine> UnregisterAsync<T>() where T : IState
|
public async Task<IStateMachine> UnregisterAsync<T>() where T : IState
|
||||||
{
|
{
|
||||||
IState? stateToUnregister;
|
var stateToUnregister = PrepareUnregister<T>(out var isCurrentState);
|
||||||
|
if (stateToUnregister == null) return this;
|
||||||
|
|
||||||
lock (_lock)
|
// 如果是当前状态,执行异步退出
|
||||||
|
if (isCurrentState)
|
||||||
{
|
{
|
||||||
var type = typeof(T);
|
await ExecuteExitAsync(Current!, null);
|
||||||
if (!States.TryGetValue(type, out stateToUnregister)) return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果当前状态是要注销的状态,则先执行退出逻辑
|
|
||||||
if (Current == stateToUnregister)
|
|
||||||
{
|
|
||||||
if (Current is IAsyncState asyncState)
|
|
||||||
await asyncState.OnExitAsync(null);
|
|
||||||
else
|
|
||||||
Current.OnExit(null);
|
|
||||||
|
|
||||||
Current = null;
|
Current = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (_lock)
|
CompleteUnregister(stateToUnregister);
|
||||||
{
|
|
||||||
// 从历史记录中移除该状态的所有引用
|
|
||||||
var tempStack = new Stack<IState>(_stateHistory.Reverse());
|
|
||||||
_stateHistory.Clear();
|
|
||||||
foreach (var historyState in tempStack.Where(s => s != stateToUnregister))
|
|
||||||
_stateHistory.Push(historyState);
|
|
||||||
|
|
||||||
States.Remove(typeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,12 +102,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
|
|
||||||
if (Current == null) return true;
|
if (Current == null) return true;
|
||||||
|
|
||||||
// 如果当前状态是异步状态,使用异步方法
|
return await CanTransitionToAsync(Current, target);
|
||||||
if (Current is IAsyncState asyncState)
|
|
||||||
return await asyncState.CanTransitionToAsync(target);
|
|
||||||
|
|
||||||
// 否则使用同步方法
|
|
||||||
return Current.CanTransitionTo(target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -146,11 +115,9 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
// 检查目标状态是否已注册
|
|
||||||
if (!States.TryGetValue(typeof(T), out var target))
|
if (!States.TryGetValue(typeof(T), out var target))
|
||||||
throw new InvalidOperationException("State not registered.");
|
throw new InvalidOperationException($"State {typeof(T).Name} not registered.");
|
||||||
|
|
||||||
// 验证当前状态是否可以转换到目标状态
|
|
||||||
if (Current != null && !Current.CanTransitionTo(target))
|
if (Current != null && !Current.CanTransitionTo(target))
|
||||||
{
|
{
|
||||||
OnTransitionRejected(Current, target);
|
OnTransitionRejected(Current, target);
|
||||||
@ -174,20 +141,14 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
// 检查目标状态是否已注册
|
|
||||||
if (!States.TryGetValue(typeof(T), out target!))
|
if (!States.TryGetValue(typeof(T), out target!))
|
||||||
throw new InvalidOperationException("State not registered.");
|
throw new InvalidOperationException($"State {typeof(T).Name} not registered.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证当前状态是否可以转换到目标状态(异步)
|
// 验证转换(在锁外执行异步操作)
|
||||||
if (Current != null)
|
if (Current != null)
|
||||||
{
|
{
|
||||||
bool canTransition;
|
var canTransition = await CanTransitionToAsync(Current, target);
|
||||||
if (Current is IAsyncState asyncState)
|
|
||||||
canTransition = await asyncState.CanTransitionToAsync(target);
|
|
||||||
else
|
|
||||||
canTransition = Current.CanTransitionTo(target);
|
|
||||||
|
|
||||||
if (!canTransition)
|
if (!canTransition)
|
||||||
{
|
{
|
||||||
await OnTransitionRejectedAsync(Current, target);
|
await OnTransitionRejectedAsync(Current, target);
|
||||||
@ -258,22 +219,12 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
||||||
public bool GoBack()
|
public bool GoBack()
|
||||||
{
|
{
|
||||||
lock (_lock)
|
var previousState = FindValidPreviousState();
|
||||||
{
|
if (previousState == null) return false;
|
||||||
if (_stateHistory.Count == 0) return false;
|
|
||||||
|
|
||||||
var previousState = _stateHistory.Pop();
|
|
||||||
|
|
||||||
// 检查上一个状态是否仍然注册
|
|
||||||
if (!States.ContainsValue(previousState))
|
|
||||||
// 如果状态已被注销,继续尝试更早的状态
|
|
||||||
return GoBack();
|
|
||||||
|
|
||||||
// 回退时不添加到历史记录
|
|
||||||
ChangeInternalWithoutHistory(previousState);
|
ChangeInternalWithoutHistory(previousState);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步回退到上一个状态
|
/// 异步回退到上一个状态
|
||||||
@ -281,28 +232,9 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
||||||
public async Task<bool> GoBackAsync()
|
public async Task<bool> GoBackAsync()
|
||||||
{
|
{
|
||||||
IState? previousState = null;
|
var previousState = FindValidPreviousState();
|
||||||
|
if (previousState == null) return false;
|
||||||
|
|
||||||
// 循环查找有效的历史状态
|
|
||||||
while (previousState == null)
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
if (_stateHistory.Count == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var candidate = _stateHistory.Pop();
|
|
||||||
|
|
||||||
// 检查状态是否仍然注册
|
|
||||||
if (States.ContainsValue(candidate))
|
|
||||||
{
|
|
||||||
previousState = candidate;
|
|
||||||
}
|
|
||||||
// 如果状态已被注销,继续循环尝试更早的状态
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 回退时不添加到历史记录
|
|
||||||
await ChangeInternalWithoutHistoryAsync(previousState);
|
await ChangeInternalWithoutHistoryAsync(previousState);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -318,6 +250,63 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 准备注销操作,返回要注销的状态
|
||||||
|
/// </summary>
|
||||||
|
private IState? PrepareUnregister<T>(out bool isCurrentState) where T : IState
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
var type = typeof(T);
|
||||||
|
if (!States.TryGetValue(type, out var state))
|
||||||
|
{
|
||||||
|
isCurrentState = false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
isCurrentState = Current == state;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 完成注销操作,清理历史记录和状态字典
|
||||||
|
/// </summary>
|
||||||
|
private void CompleteUnregister(IState stateToUnregister)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
// 从历史记录中移除该状态的所有引用
|
||||||
|
var tempStack = new Stack<IState>(_stateHistory.Reverse());
|
||||||
|
_stateHistory.Clear();
|
||||||
|
foreach (var historyState in tempStack.Where(s => s != stateToUnregister))
|
||||||
|
_stateHistory.Push(historyState);
|
||||||
|
|
||||||
|
States.Remove(stateToUnregister.GetType());
|
||||||
|
_registeredStates.Remove(stateToUnregister);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找有效的上一个状态(跳过已注销的状态)
|
||||||
|
/// </summary>
|
||||||
|
private IState? FindValidPreviousState()
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
while (_stateHistory.Count > 0)
|
||||||
|
{
|
||||||
|
var candidate = _stateHistory.Pop();
|
||||||
|
|
||||||
|
// 使用 HashSet 快速检查,O(1) 复杂度
|
||||||
|
if (_registeredStates.Contains(candidate))
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部状态切换方法(不记录历史),用于回退操作
|
/// 内部状态切换方法(不记录历史),用于回退操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -347,17 +336,9 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
var old = Current;
|
var old = Current;
|
||||||
await OnStateChangingAsync(old, next);
|
await OnStateChangingAsync(old, next);
|
||||||
|
|
||||||
if (old is IAsyncState asyncOld)
|
await ExecuteExitAsync(old, next);
|
||||||
await asyncOld.OnExitAsync(next);
|
|
||||||
else
|
|
||||||
old?.OnExit(next);
|
|
||||||
|
|
||||||
Current = next;
|
Current = next;
|
||||||
|
await ExecuteEnterAsync(Current, old);
|
||||||
if (Current is IAsyncState asyncCurrent)
|
|
||||||
await asyncCurrent.OnEnterAsync(old);
|
|
||||||
else
|
|
||||||
Current.OnEnter(old);
|
|
||||||
|
|
||||||
await OnStateChangedAsync(old, Current);
|
await OnStateChangedAsync(old, Current);
|
||||||
}
|
}
|
||||||
@ -368,10 +349,8 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <param name="next">下一个状态实例</param>
|
/// <param name="next">下一个状态实例</param>
|
||||||
protected virtual void ChangeInternal(IState next)
|
protected virtual void ChangeInternal(IState next)
|
||||||
{
|
{
|
||||||
// 检查是否为相同状态,避免不必要的切换
|
|
||||||
if (Current == next) return;
|
if (Current == next) return;
|
||||||
|
|
||||||
// 验证当前状态是否允许切换到目标状态
|
|
||||||
if (Current != null && !Current.CanTransitionTo(next))
|
if (Current != null && !Current.CanTransitionTo(next))
|
||||||
{
|
{
|
||||||
OnTransitionRejected(Current, next);
|
OnTransitionRejected(Current, next);
|
||||||
@ -381,20 +360,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
var old = Current;
|
var old = Current;
|
||||||
OnStateChanging(old, next);
|
OnStateChanging(old, next);
|
||||||
|
|
||||||
// 将当前状态添加到历史记录
|
AddToHistory(Current);
|
||||||
if (Current != null)
|
|
||||||
{
|
|
||||||
_stateHistory.Push(Current);
|
|
||||||
|
|
||||||
// 限制历史记录大小
|
|
||||||
if (_stateHistory.Count > maxHistorySize)
|
|
||||||
{
|
|
||||||
// 移除最旧的记录(栈底元素)
|
|
||||||
var tempStack = new Stack<IState>(_stateHistory.Reverse().Skip(1));
|
|
||||||
_stateHistory.Clear();
|
|
||||||
foreach (var state in tempStack.Reverse()) _stateHistory.Push(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
old?.OnExit(next);
|
old?.OnExit(next);
|
||||||
Current = next;
|
Current = next;
|
||||||
@ -409,45 +375,77 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <param name="next">下一个状态实例</param>
|
/// <param name="next">下一个状态实例</param>
|
||||||
protected virtual async Task ChangeInternalAsync(IState next)
|
protected virtual async Task ChangeInternalAsync(IState next)
|
||||||
{
|
{
|
||||||
// 检查是否为相同状态,避免不必要的切换
|
|
||||||
if (Current == next) return;
|
if (Current == next) return;
|
||||||
|
|
||||||
var old = Current;
|
var old = Current;
|
||||||
await OnStateChangingAsync(old, next);
|
await OnStateChangingAsync(old, next);
|
||||||
|
|
||||||
// 将当前状态添加到历史记录
|
AddToHistory(Current);
|
||||||
|
|
||||||
|
await ExecuteExitAsync(old, next);
|
||||||
|
Current = next;
|
||||||
|
await ExecuteEnterAsync(Current, old);
|
||||||
|
|
||||||
|
await OnStateChangedAsync(old, Current);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将状态添加到历史记录
|
||||||
|
/// </summary>
|
||||||
|
private void AddToHistory(IState? state)
|
||||||
|
{
|
||||||
|
if (state == null) return;
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (Current != null)
|
_stateHistory.Push(state);
|
||||||
{
|
|
||||||
_stateHistory.Push(Current);
|
|
||||||
|
|
||||||
// 限制历史记录大小
|
// 限制历史记录大小
|
||||||
if (_stateHistory.Count > maxHistorySize)
|
if (_stateHistory.Count > maxHistorySize)
|
||||||
{
|
{
|
||||||
// 移除最旧的记录(栈底元素)
|
|
||||||
var tempStack = new Stack<IState>(_stateHistory.Reverse().Skip(1));
|
var tempStack = new Stack<IState>(_stateHistory.Reverse().Skip(1));
|
||||||
_stateHistory.Clear();
|
_stateHistory.Clear();
|
||||||
foreach (var state in tempStack.Reverse()) _stateHistory.Push(state);
|
foreach (var s in tempStack.Reverse())
|
||||||
|
_stateHistory.Push(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行退出逻辑(异步或同步)
|
/// <summary>
|
||||||
if (old is IAsyncState asyncOld)
|
/// 执行状态进入逻辑(智能判断同步/异步)
|
||||||
await asyncOld.OnExitAsync(next);
|
/// </summary>
|
||||||
|
private static async Task ExecuteEnterAsync(IState? state, IState? from)
|
||||||
|
{
|
||||||
|
if (state == null) return;
|
||||||
|
|
||||||
|
if (state is IAsyncState asyncState)
|
||||||
|
await asyncState.OnEnterAsync(from);
|
||||||
else
|
else
|
||||||
old?.OnExit(next);
|
state.OnEnter(from);
|
||||||
|
}
|
||||||
|
|
||||||
Current = next;
|
/// <summary>
|
||||||
|
/// 执行状态退出逻辑(智能判断同步/异步)
|
||||||
|
/// </summary>
|
||||||
|
private static async Task ExecuteExitAsync(IState? state, IState? to)
|
||||||
|
{
|
||||||
|
if (state == null) return;
|
||||||
|
|
||||||
// 执行进入逻辑(异步或同步)
|
if (state is IAsyncState asyncState)
|
||||||
if (Current is IAsyncState asyncCurrent)
|
await asyncState.OnExitAsync(to);
|
||||||
await asyncCurrent.OnEnterAsync(old);
|
|
||||||
else
|
else
|
||||||
Current.OnEnter(old);
|
state.OnExit(to);
|
||||||
|
}
|
||||||
|
|
||||||
await OnStateChangedAsync(old, Current);
|
/// <summary>
|
||||||
|
/// 检查是否可以转换到目标状态(智能判断同步/异步)
|
||||||
|
/// </summary>
|
||||||
|
private static async Task<bool> CanTransitionToAsync(IState current, IState target)
|
||||||
|
{
|
||||||
|
if (current is IAsyncState asyncState)
|
||||||
|
return await asyncState.CanTransitionToAsync(target);
|
||||||
|
|
||||||
|
return current.CanTransitionTo(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user