feat(core): 扩展ContextAwareExtensions功能并增强状态机系统

- 在ContextAwareExtensions中添加事件发送、注册和取消注册方法
- 添加环境对象获取功能
- 扩展命令和查询功能支持同步、异步及中介者模式
- 添加统一请求处理方法和便捷扩展方法
- 为StateMachineSystem添加异步状态切换事件通知功能
- 添加状态机异步操作相关单元测试
- 扩展现有测试类以覆盖新增功能
- [release ci]
This commit is contained in:
GeWuYou 2026-02-15 18:55:15 +08:00 committed by gewuyou
parent 7e2a1ff66d
commit 38967d047a
5 changed files with 1187 additions and 86 deletions

View File

@ -270,6 +270,93 @@ public class StateMachineSystemTests
_stateMachine.Destroy();
}
/// <summary>
/// 测试异步ChangeToAsync发送StateChangedEvent事件
/// 验证当状态机使用异步方法切换到新状态时会正确触发StateChangedEvent事件
/// </summary>
[Test]
public async Task ChangeToAsync_Should_Send_StateChangedEvent()
{
var eventReceived = false;
StateChangedEvent? receivedEvent = null;
_eventBus!.Register<StateChangedEvent>(e =>
{
eventReceived = true;
receivedEvent = e;
});
var state1 = new TestStateV5();
var state2 = new TestStateV5();
_stateMachine!.Register(state1);
_stateMachine.Register(state2);
_stateMachine.Init();
await _stateMachine.ChangeToAsync<TestStateV5>();
Assert.That(eventReceived, Is.True);
Assert.That(receivedEvent!.OldState, Is.Null);
Assert.That(receivedEvent.NewState, Is.InstanceOf<TestStateV5>());
}
/// <summary>
/// 测试异步ChangeToAsync发送StateChangedEvent事件包含旧状态
/// 验证当状态机使用异步方法从一个状态切换到另一个状态时会正确触发StateChangedEvent事件
/// </summary>
[Test]
public async Task ChangeToAsync_Should_Send_StateChangedEvent_With_OldState()
{
var eventReceived = false;
StateChangedEvent? receivedEvent = null;
_eventBus!.Register<StateChangedEvent>(e =>
{
eventReceived = true;
receivedEvent = e;
});
var state1 = new TestStateV5();
var state2 = new TestStateV5_2();
_stateMachine!.Register(state1);
_stateMachine.Register(state2);
_stateMachine.Init();
await _stateMachine.ChangeToAsync<TestStateV5>();
eventReceived = false;
await _stateMachine.ChangeToAsync<TestStateV5_2>();
Assert.That(eventReceived, Is.True);
Assert.That(receivedEvent!.OldState, Is.InstanceOf<TestStateV5>());
Assert.That(receivedEvent.NewState, Is.InstanceOf<TestStateV5_2>());
}
/// <summary>
/// 测试异步切换时多次状态变更都能正确触发事件
/// </summary>
[Test]
public async Task ChangeToAsync_MultipleChanges_Should_Send_Events_Correctly()
{
var eventCount = 0;
_eventBus!.Register<StateChangedEvent>(_ => { eventCount++; });
var state1 = new TestStateV5();
var state2 = new TestStateV5_2();
_stateMachine!.Register(state1);
_stateMachine.Register(state2);
_stateMachine.Init();
await _stateMachine.ChangeToAsync<TestStateV5>();
await _stateMachine.ChangeToAsync<TestStateV5_2>();
await _stateMachine.ChangeToAsync<TestStateV5>();
Assert.That(eventCount, Is.EqualTo(3));
}
}
#region Test Classes
@ -370,4 +457,41 @@ public class TestStateV5 : IState
}
}
/// <summary>
/// 第二个测试用的普通状态实现,用于区分不同状态类型
/// </summary>
public class TestStateV5_2 : IState
{
/// <summary>
/// 状态标识符
/// </summary>
public int Id { get; set; }
/// <summary>
/// 检查是否可以转换到指定状态
/// </summary>
/// <param name="next">目标状态</param>
/// <returns>始终返回true表示允许转换</returns>
public bool CanTransitionTo(IState next)
{
return true;
}
/// <summary>
/// 进入状态时调用
/// </summary>
/// <param name="previous">前一个状态</param>
public void OnEnter(IState? previous)
{
}
/// <summary>
/// 退出状态时调用
/// </summary>
/// <param name="next">下一个状态</param>
public void OnExit(IState? next)
{
}
}
#endregion

View File

@ -241,6 +241,394 @@ public class StateMachineTests
Assert.That(_stateMachine.Current, Is.SameAs(state1));
}
/// <summary>
/// 验证异步注销后状态应从字典中移除
/// </summary>
[Test]
public async Task UnregisterAsync_Should_RemoveState_FromDictionary()
{
var state = new TestStateV2();
_stateMachine.Register(state);
await _stateMachine.UnregisterAsync<TestStateV2>();
Assert.That(_stateMachine.ContainsState<TestStateV2>(), Is.False);
}
/// <summary>
/// 验证异步注销活动同步状态时调用OnExit
/// </summary>
[Test]
public async Task UnregisterAsync_WhenStateIsActive_WithSyncState_Should_Invoke_OnExit()
{
var state = new TestStateV2();
_stateMachine.Register(state);
_stateMachine.ChangeTo<TestStateV2>();
await _stateMachine.UnregisterAsync<TestStateV2>();
Assert.That(state.ExitCalled, Is.True);
Assert.That(state.ExitTo, Is.Null);
Assert.That(_stateMachine.Current, Is.Null);
}
/// <summary>
/// 验证异步注销活动异步状态时调用OnExitAsync
/// </summary>
[Test]
public async Task UnregisterAsync_WhenStateIsActive_WithAsyncState_Should_Invoke_OnExitAsync()
{
var state = new TestAsyncState();
_stateMachine.Register(state);
await _stateMachine.ChangeToAsync<TestAsyncState>();
await _stateMachine.UnregisterAsync<TestAsyncState>();
Assert.That(state.ExitCalled, Is.True);
Assert.That(state.ExitTo, Is.Null);
Assert.That(_stateMachine.Current, Is.Null);
}
/// <summary>
/// 验证异步注销非活动状态不调用退出方法
/// </summary>
[Test]
public async Task UnregisterAsync_WhenStateNotActive_Should_Not_Invoke_Exit()
{
var state1 = new TestStateV2();
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.ChangeTo<TestStateV2>();
await _stateMachine.UnregisterAsync<TestStateV3>();
Assert.That(state1.ExitCalled, Is.False);
Assert.That(_stateMachine.Current, Is.SameAs(state1));
}
/// <summary>
/// 验证异步切换检查未注册状态返回false
/// </summary>
[Test]
public async Task CanChangeToAsync_WhenStateNotRegistered_Should_ReturnFalse()
{
var result = await _stateMachine.CanChangeToAsync<TestStateV2>();
Assert.That(result, Is.False);
}
/// <summary>
/// 验证异步切换检查已注册状态返回true
/// </summary>
[Test]
public async Task CanChangeToAsync_WhenStateRegistered_Should_ReturnTrue()
{
var state = new TestStateV2();
_stateMachine.Register(state);
var result = await _stateMachine.CanChangeToAsync<TestStateV2>();
Assert.That(result, Is.True);
}
/// <summary>
/// 验证异步切换检查当前状态拒绝转换时返回false
/// </summary>
[Test]
public async Task CanChangeToAsync_WhenCurrentStateDeniesTransition_Should_ReturnFalse()
{
var state1 = new TestStateV2 { AllowTransition = false };
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.ChangeTo<TestStateV2>();
var result = await _stateMachine.CanChangeToAsync<TestStateV3>();
Assert.That(result, Is.False);
}
/// <summary>
/// 验证异步切换检查使用异步状态时调用CanTransitionToAsync
/// </summary>
[Test]
public async Task CanChangeToAsync_WithAsyncState_Should_Call_CanTransitionToAsync()
{
var state1 = new TestAsyncState();
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
await _stateMachine.ChangeToAsync<TestAsyncState>();
await _stateMachine.CanChangeToAsync<TestStateV3>();
Assert.That(state1.CanTransitionToCallCount, Is.EqualTo(1));
}
/// <summary>
/// 验证异步切换检查使用同步状态时调用CanTransitionTo
/// </summary>
[Test]
public async Task CanChangeToAsync_WithSyncState_Should_Call_CanTransitionTo()
{
var state1 = new TestStateV2 { AllowTransition = false };
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.ChangeTo<TestStateV2>();
var result = await _stateMachine.CanChangeToAsync<TestStateV3>();
Assert.That(result, Is.False);
}
/// <summary>
/// 验证异步状态切换能够正确设置当前状态
/// </summary>
[Test]
public async Task ChangeToAsync_Should_SetCurrentState()
{
var state = new TestStateV2();
_stateMachine.Register(state);
await _stateMachine.ChangeToAsync<TestStateV2>();
Assert.That(_stateMachine.Current, Is.SameAs(state));
}
/// <summary>
/// 验证异步状态切换对于异步状态调用OnEnterAsync
/// </summary>
[Test]
public async Task ChangeToAsync_Should_Invoke_OnEnterAsync_ForAsyncState()
{
var state = new TestAsyncState();
_stateMachine.Register(state);
await _stateMachine.ChangeToAsync<TestAsyncState>();
Assert.That(state.EnterCalled, Is.True);
Assert.That(state.EnterFrom, Is.Null);
}
/// <summary>
/// 验证异步状态切换对于同步状态调用OnEnter
/// </summary>
[Test]
public async Task ChangeToAsync_Should_Invoke_OnEnter_ForSyncState()
{
var state = new TestStateV2();
_stateMachine.Register(state);
await _stateMachine.ChangeToAsync<TestStateV2>();
Assert.That(state.EnterCalled, Is.True);
Assert.That(state.EnterFrom, Is.Null);
}
/// <summary>
/// 验证异步状态切换当存在当前异步状态时调用OnExitAsync
/// </summary>
[Test]
public async Task ChangeToAsync_When_CurrentStateExists_WithAsyncState_Should_Invoke_OnExitAsync()
{
var state1 = new TestAsyncState();
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
await _stateMachine.ChangeToAsync<TestAsyncState>();
await _stateMachine.ChangeToAsync<TestStateV3>();
Assert.That(state1.ExitCalled, Is.True);
Assert.That(state1.ExitTo, Is.SameAs(state2));
}
/// <summary>
/// 验证异步状态切换当存在当前同步状态时调用OnExit
/// </summary>
[Test]
public async Task ChangeToAsync_When_CurrentStateExists_WithSyncState_Should_Invoke_OnExit()
{
var state1 = new TestStateV2();
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
await _stateMachine.ChangeToAsync<TestStateV2>();
await _stateMachine.ChangeToAsync<TestStateV3>();
Assert.That(state1.ExitCalled, Is.True);
Assert.That(state1.ExitTo, Is.SameAs(state2));
}
/// <summary>
/// 验证异步状态切换到相同状态时不应调用回调方法
/// </summary>
[Test]
public async Task ChangeToAsync_ToSameState_Should_NotInvoke_Callbacks()
{
var state = new TestStateV2();
_stateMachine.Register(state);
await _stateMachine.ChangeToAsync<TestStateV2>();
var enterCount = state.EnterCallCount;
var exitCount = state.ExitCallCount;
await _stateMachine.ChangeToAsync<TestStateV2>();
Assert.That(state.EnterCallCount, Is.EqualTo(enterCount));
Assert.That(state.ExitCallCount, Is.EqualTo(exitCount));
}
/// <summary>
/// 验证异步状态切换到未注册状态时应抛出InvalidOperationException
/// </summary>
[Test]
public void ChangeToAsync_ToUnregisteredState_Should_ThrowInvalidOperationException()
{
Assert.ThrowsAsync<InvalidOperationException>(async () => await _stateMachine.ChangeToAsync<TestStateV2>());
}
/// <summary>
/// 验证异步状态切换当当前状态拒绝转换时不应发生状态变化
/// </summary>
[Test]
public async Task ChangeToAsync_WhenCurrentStateDeniesTransition_Should_NotChange()
{
var state1 = new TestStateV2 { AllowTransition = false };
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
await _stateMachine.ChangeToAsync<TestStateV2>();
var oldState = _stateMachine.Current;
var result = await _stateMachine.ChangeToAsync<TestStateV3>();
Assert.That(result, Is.False);
Assert.That(_stateMachine.Current, Is.SameAs(oldState));
Assert.That(_stateMachine.Current, Is.SameAs(state1));
Assert.That(state2.EnterCalled, Is.False);
}
/// <summary>
/// 验证异步状态切换当当前异步状态拒绝转换时调用CanTransitionToAsync
/// </summary>
[Test]
public async Task ChangeToAsync_WhenCurrentStateDeniesTransition_WithAsyncState_Should_Call_CanTransitionToAsync()
{
var state1 = new TestAsyncState { AllowTransition = false };
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
await _stateMachine.ChangeToAsync<TestAsyncState>();
await _stateMachine.ChangeToAsync<TestStateV3>();
Assert.That(state1.CanTransitionToCallCount, Is.EqualTo(1));
}
/// <summary>
/// 验证异步回退能够返回到上一个状态
/// </summary>
[Test]
public async Task GoBackAsync_Should_ReturnTo_PreviousState()
{
var state1 = new TestStateV2();
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
await _stateMachine.ChangeToAsync<TestStateV2>();
await _stateMachine.ChangeToAsync<TestStateV3>();
var result = await _stateMachine.GoBackAsync();
Assert.That(result, Is.True);
Assert.That(_stateMachine.Current, Is.SameAs(state1));
}
/// <summary>
/// 验证异步回退当没有历史记录时返回false
/// </summary>
[Test]
public async Task GoBackAsync_WhenNoHistory_Should_ReturnFalse()
{
var result = await _stateMachine.GoBackAsync();
Assert.That(result, Is.False);
}
/// <summary>
/// 验证异步回退调用正确的状态转换方法
/// </summary>
[Test]
public async Task GoBackAsync_Should_Invoke_Correct_Transition_Methods()
{
var state1 = new TestAsyncState();
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
await _stateMachine.ChangeToAsync<TestAsyncState>();
await _stateMachine.ChangeToAsync<TestStateV3>();
await _stateMachine.GoBackAsync();
Assert.That(state2.ExitCalled, Is.True);
Assert.That(state1.EnterCallCount, Is.EqualTo(2));
}
/// <summary>
/// 验证从同步状态切换到异步状态能够正常工作
/// </summary>
[Test]
public async Task ChangeToAsync_FromSyncToAsyncState_Should_Work()
{
var state1 = new TestStateV2();
var state2 = new TestAsyncState();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
await _stateMachine.ChangeToAsync<TestStateV2>();
await _stateMachine.ChangeToAsync<TestAsyncState>();
Assert.That(state1.ExitCalled, Is.True);
Assert.That(state2.EnterCalled, Is.True);
Assert.That(_stateMachine.Current, Is.SameAs(state2));
}
/// <summary>
/// 验证从异步状态切换到同步状态能够正常工作
/// </summary>
[Test]
public async Task ChangeToAsync_FromAsyncToSyncState_Should_Work()
{
var state1 = new TestAsyncState();
var state2 = new TestStateV2();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
await _stateMachine.ChangeToAsync<TestAsyncState>();
await _stateMachine.ChangeToAsync<TestStateV2>();
Assert.That(state1.ExitCalled, Is.True);
Assert.That(state2.EnterCalled, Is.True);
Assert.That(_stateMachine.Current, Is.SameAs(state2));
}
/// <summary>
/// 验证多次异步状态转换应正确调用回调方法
/// </summary>
[Test]
public async Task MultipleAsyncStateChanges_Should_Invoke_Callbacks_Correctly()
{
var state1 = new TestAsyncState();
var state2 = new TestStateV2();
var state3 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.Register(state3);
await _stateMachine.ChangeToAsync<TestAsyncState>();
await _stateMachine.ChangeToAsync<TestStateV2>();
await _stateMachine.ChangeToAsync<TestStateV3>();
Assert.That(state1.EnterCalled, Is.True);
Assert.That(state1.ExitCalled, Is.True);
Assert.That(state2.EnterCalled, Is.True);
Assert.That(state2.ExitCalled, Is.True);
Assert.That(state3.EnterCalled, Is.True);
Assert.That(state3.ExitCalled, Is.False);
}
/// <summary>
/// 验证多次状态转换应正确调用回调方法
/// </summary>
@ -424,6 +812,85 @@ public sealed class TestStateV4 : IState
}
}
/// <summary>
/// 异步测试状态类同时实现IState和IAsyncState接口用于测试异步状态功能
/// </summary>
public sealed class TestAsyncState : IState, IAsyncState
{
public bool AllowTransition { get; set; } = true;
public bool EnterCalled { get; private set; }
public bool ExitCalled { get; private set; }
public int EnterCallCount { get; private set; }
public int ExitCallCount { get; private set; }
public IState? EnterFrom { get; private set; }
public IState? ExitTo { get; private set; }
public int CanTransitionToCallCount { get; private set; }
/// <summary>
/// 异步进入状态时的回调方法
/// </summary>
/// <param name="from">从哪个状态进入</param>
public async Task OnEnterAsync(IState? from)
{
await Task.Delay(1);
EnterCalled = true;
EnterCallCount++;
EnterFrom = from;
}
/// <summary>
/// 异步离开状态时的回调方法
/// </summary>
/// <param name="to">离开到哪个状态</param>
public async Task OnExitAsync(IState? to)
{
await Task.Delay(1);
ExitCalled = true;
ExitCallCount++;
ExitTo = to;
}
/// <summary>
/// 异步判断是否可以转换到目标状态
/// </summary>
/// <param name="target">目标状态</param>
/// <returns>是否允许转换</returns>
public async Task<bool> CanTransitionToAsync(IState target)
{
await Task.Delay(1);
CanTransitionToCallCount++;
return AllowTransition;
}
/// <summary>
/// 进入状态时的回调方法(同步版本,抛出异常表示不应被调用)
/// </summary>
/// <param name="from">从哪个状态进入</param>
public void OnEnter(IState? from)
{
throw new InvalidOperationException("Sync OnEnter should not be called for async state");
}
/// <summary>
/// 离开状态时的回调方法(同步版本,抛出异常表示不应被调用)
/// </summary>
/// <param name="to">离开到哪个状态</param>
public void OnExit(IState? to)
{
throw new InvalidOperationException("Sync OnExit should not be called for async state");
}
/// <summary>
/// 判断是否可以转换到目标状态(同步版本,抛出异常表示不应被调用)
/// </summary>
/// <param name="target">目标状态</param>
/// <returns>是否允许转换</returns>
public bool CanTransitionTo(IState target)
{
throw new InvalidOperationException("Sync CanTransitionTo should not be called for async state");
}
}
/// <summary>
/// 状态机扩展方法类
/// </summary>

View File

@ -194,6 +194,137 @@ public class StateTests
Assert.That(state2.EnterFrom, Is.SameAs(state1));
Assert.That(state3.EnterFrom, Is.SameAs(state2));
}
/// <summary>
/// 验证异步状态类是否正确实现了IAsyncState接口
/// </summary>
[Test]
public void AsyncState_Should_Implement_IAsyncState_Interface()
{
var state = new ConcreteAsyncStateV2();
Assert.That(state is IAsyncState);
}
/// <summary>
/// 验证进入异步状态时OnEnterAsync方法被正确调用并记录来源状态
/// </summary>
[Test]
public async Task OnEnterAsync_Should_BeCalled_When_AsyncState_Enters()
{
var state = new ConcreteAsyncStateV2();
var otherState = new ConcreteStateV3();
await state.OnEnterAsync(otherState);
Assert.That(state.EnterCalled, Is.True);
Assert.That(state.EnterFrom, Is.SameAs(otherState));
}
/// <summary>
/// 验证当传入null作为来源状态时异步状态的处理情况
/// </summary>
[Test]
public async Task OnEnterAsync_WithNull_Should_Set_EnterFrom_ToNull()
{
var state = new ConcreteAsyncStateV2();
await state.OnEnterAsync(null);
Assert.That(state.EnterCalled, Is.True);
Assert.That(state.EnterFrom, Is.Null);
}
/// <summary>
/// 验证退出异步状态时OnExitAsync方法被正确调用并记录目标状态
/// </summary>
[Test]
public async Task OnExitAsync_Should_BeCalled_When_AsyncState_Exits()
{
var state = new ConcreteAsyncStateV2();
var otherState = new ConcreteStateV3();
await state.OnExitAsync(otherState);
Assert.That(state.ExitCalled, Is.True);
Assert.That(state.ExitTo, Is.SameAs(otherState));
}
/// <summary>
/// 验证当传入null作为目标状态时异步状态的处理情况
/// </summary>
[Test]
public async Task OnExitAsync_WithNull_Should_Set_ExitTo_ToNull()
{
var state = new ConcreteAsyncStateV2();
await state.OnExitAsync(null);
Assert.That(state.ExitCalled, Is.True);
Assert.That(state.ExitTo, Is.Null);
}
/// <summary>
/// 验证允许转换时CanTransitionToAsync方法返回true
/// </summary>
[Test]
public async Task CanTransitionToAsync_WithAllowTrue_Should_ReturnTrue()
{
var state = new ConcreteAsyncStateV2 { AllowTransitions = true };
var target = new ConcreteStateV3();
var result = await state.CanTransitionToAsync(target);
Assert.That(result, Is.True);
}
/// <summary>
/// 验证不允许转换时CanTransitionToAsync方法返回false
/// </summary>
[Test]
public async Task CanTransitionToAsync_WithAllowFalse_Should_ReturnFalse()
{
var state = new ConcreteAsyncStateV2 { AllowTransitions = false };
var target = new ConcreteStateV3();
var result = await state.CanTransitionToAsync(target);
Assert.That(result, Is.False);
}
/// <summary>
/// 验证CanTransitionToAsync方法正确接收目标状态参数
/// </summary>
[Test]
public async Task CanTransitionToAsync_Should_Receive_TargetState()
{
var state = new ConcreteAsyncStateV2 { AllowTransitions = true };
var target = new ConcreteStateV3();
IState? receivedTarget = null;
state.CanTransitionToAsyncAction = s => receivedTarget = s;
await state.CanTransitionToAsync(target);
Assert.That(receivedTarget, Is.SameAs(target));
}
/// <summary>
/// 验证异步状态对多次转换的跟踪能力
/// </summary>
[Test]
public async Task AsyncState_Should_Track_MultipleTransitions()
{
var state = new ConcreteAsyncStateV2();
var other = new ConcreteStateV3();
await state.OnEnterAsync(other);
await state.OnExitAsync(other);
await state.OnEnterAsync(other);
await state.OnExitAsync(null);
Assert.That(state.EnterCallCount, Is.EqualTo(2));
Assert.That(state.ExitCallCount, Is.EqualTo(2));
}
}
/// <summary>
@ -490,4 +621,114 @@ public sealed class TrackingStateV2 : IState
{
return true;
}
}
/// <summary>
/// 异步具体状态实现类V2版本用于测试异步状态的基本功能
/// </summary>
public sealed class ConcreteAsyncStateV2 : IState, IAsyncState
{
/// <summary>
/// 获取或设置是否允许转换
/// </summary>
public bool AllowTransitions { get; set; } = true;
/// <summary>
/// 获取进入状态是否被调用的标志
/// </summary>
public bool EnterCalled { get; private set; }
/// <summary>
/// 获取退出状态是否被调用的标志
/// </summary>
public bool ExitCalled { get; private set; }
/// <summary>
/// 获取进入状态被调用的次数
/// </summary>
public int EnterCallCount { get; private set; }
/// <summary>
/// 获取退出状态被调用的次数
/// </summary>
public int ExitCallCount { get; private set; }
/// <summary>
/// 获取进入此状态的来源状态
/// </summary>
public IState? EnterFrom { get; private set; }
/// <summary>
/// 获取从此状态退出的目标状态
/// </summary>
public IState? ExitTo { get; private set; }
/// <summary>
/// 获取或设置转换到目标状态时执行的动作
/// </summary>
public Action<IState>? CanTransitionToAsyncAction { get; set; }
/// <summary>
/// 异步进入当前状态时调用的方法
/// </summary>
/// <param name="from">从哪个状态进入</param>
public async Task OnEnterAsync(IState? from)
{
await Task.Delay(1);
EnterCalled = true;
EnterCallCount++;
EnterFrom = from;
}
/// <summary>
/// 异步退出当前状态时调用的方法
/// </summary>
/// <param name="to">退出到哪个状态</param>
public async Task OnExitAsync(IState? to)
{
await Task.Delay(1);
ExitCalled = true;
ExitCallCount++;
ExitTo = to;
}
/// <summary>
/// 异步判断是否可以转换到目标状态
/// </summary>
/// <param name="target">目标状态</param>
/// <returns>如果可以转换则返回true否则返回false</returns>
public async Task<bool> CanTransitionToAsync(IState target)
{
await Task.Delay(1);
CanTransitionToAsyncAction?.Invoke(target);
return AllowTransitions;
}
/// <summary>
/// 进入当前状态时调用的方法(同步版本,抛出异常表示不应被调用)
/// </summary>
/// <param name="from">从哪个状态进入</param>
public void OnEnter(IState? from)
{
throw new InvalidOperationException("Sync OnEnter should not be called for async state");
}
/// <summary>
/// 退出当前状态时调用的方法(同步版本,抛出异常表示不应被调用)
/// </summary>
/// <param name="to">退出到哪个状态</param>
public void OnExit(IState? to)
{
throw new InvalidOperationException("Sync OnExit should not be called for async state");
}
/// <summary>
/// 判断是否可以转换到目标状态(同步版本,抛出异常表示不应被调用)
/// </summary>
/// <param name="target">目标状态</param>
/// <returns>如果可以转换则返回true否则返回false</returns>
public bool CanTransitionTo(IState target)
{
throw new InvalidOperationException("Sync CanTransitionTo should not be called for async state");
}
}

View File

@ -6,6 +6,7 @@ using GFramework.Core.Abstractions.query;
using GFramework.Core.Abstractions.rule;
using GFramework.Core.Abstractions.system;
using GFramework.Core.Abstractions.utility;
using Mediator;
namespace GFramework.Core.extensions;
@ -19,7 +20,7 @@ public static class ContextAwareExtensions
/// </summary>
/// <typeparam name="TService">要获取的服务类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的上下文感知对象</param>
/// <returns>指定类型的服务实例如果未找到则返回 null</returns>
/// <returns>指定类型的服务实例,如果未找到则返回 null</returns>
/// <exception cref="ArgumentNullException">当 contextAware 参数为 null 时抛出</exception>
public static TService? GetService<TService>(this IContextAware contextAware) where TService : class
{
@ -71,56 +72,6 @@ public static class ContextAwareExtensions
return context.GetUtility<TUtility>();
}
/// <summary>
/// 发送一个查询请求
/// </summary>
/// <typeparam name="TResult">查询结果类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="query">要发送的查询</param>
/// <returns>查询结果</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 query 为 null 时抛出</exception>
public static TResult SendQuery<TResult>(this IContextAware contextAware, IQuery<TResult> query)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(query);
var context = contextAware.GetContext();
return context.SendQuery(query);
}
/// <summary>
/// 发送并异步执行一个无返回值的命令
/// </summary>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="command">要发送的命令</param>
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static async Task SendCommandAsync(this IContextAware contextAware, IAsyncCommand command)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(command);
var context = contextAware.GetContext();
await context.SendCommandAsync(command);
}
/// <summary>
/// 发送并异步执行一个带返回值的命令
/// </summary>
/// <typeparam name="TResult">命令执行结果类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="command">要发送的命令</param>
/// <returns>命令执行结果</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static async Task<TResult> SendCommandAsync<TResult>(this IContextAware contextAware,
IAsyncCommand<TResult> command)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(command);
var context = contextAware.GetContext();
return await context.SendCommandAsync(command);
}
/// <summary>
/// 发送一个事件
@ -151,39 +102,6 @@ public static class ContextAwareExtensions
context.SendEvent(e);
}
/// <summary>
/// 发送一个事件
/// </summary>
/// <typeparam name="TResult">命令执行结果类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="command">要发送的命令</param>
/// <returns>命令执行结果</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static TResult SendCommand<TResult>(this IContextAware contextAware, ICommand<TResult> command)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(command);
var context = contextAware.GetContext();
return context.SendCommand(command);
}
/// <summary>
/// 发送一个无返回结果的命令
/// </summary>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="command">要发送的命令</param>
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static void SendCommand(this IContextAware contextAware, ICommand command)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(command);
var context = contextAware.GetContext();
context.SendCommand(command);
}
/// <summary>
/// 注册事件处理器
/// </summary>
@ -222,7 +140,7 @@ public static class ContextAwareExtensions
/// </summary>
/// <typeparam name="T">要获取的环境对象类型</typeparam>
/// <param name="contextAware">上下文感知对象</param>
/// <returns>指定类型的环境对象如果无法转换则返回null</returns>
/// <returns>指定类型的环境对象,如果无法转换则返回null</returns>
public static T? GetEnvironment<T>(this IContextAware contextAware) where T : class
{
ArgumentNullException.ThrowIfNull(contextAware);
@ -243,4 +161,338 @@ public static class ContextAwareExtensions
var context = contextAware.GetContext();
return context.GetEnvironment();
}
/// <summary>
/// [Mediator] 发送命令的同步版本(不推荐,仅用于兼容性)
/// </summary>
/// <typeparam name="TResponse">命令响应类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="command">要发送的命令对象</param>
/// <returns>命令执行结果</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static TResponse SendCommand<TResponse>(this IContextAware contextAware,
Mediator.ICommand<TResponse> command)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(command);
var context = contextAware.GetContext();
return context.SendCommand(command);
}
/// <summary>
/// 发送一个带返回结果的命令
/// </summary>
/// <typeparam name="TResult">命令执行结果类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="command">要发送的命令</param>
/// <returns>命令执行结果</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static TResult SendCommand<TResult>(this IContextAware contextAware,
Abstractions.command.ICommand<TResult> command)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(command);
var context = contextAware.GetContext();
return context.SendCommand(command);
}
/// <summary>
/// 发送一个无返回结果的命令
/// </summary>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="command">要发送的命令</param>
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static void SendCommand(this IContextAware contextAware, Abstractions.command.ICommand command)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(command);
var context = contextAware.GetContext();
context.SendCommand(command);
}
/// <summary>
/// [Mediator] 异步发送命令并返回结果
/// </summary>
/// <typeparam name="TResponse">命令响应类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="command">要发送的命令对象</param>
/// <param name="cancellationToken">取消令牌,用于取消操作</param>
/// <returns>包含命令执行结果的ValueTask</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static ValueTask<TResponse> SendCommandAsync<TResponse>(this IContextAware contextAware,
Mediator.ICommand<TResponse> command, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(command);
var context = contextAware.GetContext();
return context.SendCommandAsync(command, cancellationToken);
}
/// <summary>
/// 发送并异步执行一个无返回值的命令
/// </summary>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="command">要发送的命令</param>
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static async Task SendCommandAsync(this IContextAware contextAware, IAsyncCommand command)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(command);
var context = contextAware.GetContext();
await context.SendCommandAsync(command);
}
/// <summary>
/// 发送并异步执行一个带返回值的命令
/// </summary>
/// <typeparam name="TResult">命令执行结果类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="command">要发送的命令</param>
/// <returns>命令执行结果</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static async Task<TResult> SendCommandAsync<TResult>(this IContextAware contextAware,
IAsyncCommand<TResult> command)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(command);
var context = contextAware.GetContext();
return await context.SendCommandAsync(command);
}
/// <summary>
/// [Mediator] 发送查询的同步版本(不推荐,仅用于兼容性)
/// </summary>
/// <typeparam name="TResponse">查询响应类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="query">要发送的查询对象</param>
/// <returns>查询结果</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 query 为 null 时抛出</exception>
public static TResponse SendQuery<TResponse>(this IContextAware contextAware, Mediator.IQuery<TResponse> query)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(query);
var context = contextAware.GetContext();
return context.SendQuery(query);
}
/// <summary>
/// 发送一个查询请求
/// </summary>
/// <typeparam name="TResult">查询结果类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="query">要发送的查询</param>
/// <returns>查询结果</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 query 为 null 时抛出</exception>
public static TResult SendQuery<TResult>(this IContextAware contextAware, Abstractions.query.IQuery<TResult> query)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(query);
var context = contextAware.GetContext();
return context.SendQuery(query);
}
/// <summary>
/// [Mediator] 异步发送查询并返回结果
/// </summary>
/// <typeparam name="TResponse">查询响应类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="query">要发送的查询对象</param>
/// <param name="cancellationToken">取消令牌,用于取消操作</param>
/// <returns>包含查询结果的ValueTask</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 query 为 null 时抛出</exception>
public static ValueTask<TResponse> SendQueryAsync<TResponse>(this IContextAware contextAware,
Mediator.IQuery<TResponse> query, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(query);
var context = contextAware.GetContext();
return context.SendQueryAsync(query, cancellationToken);
}
/// <summary>
/// 异步发送一个查询请求
/// </summary>
/// <typeparam name="TResult">查询结果类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="query">要发送的异步查询</param>
/// <returns>查询结果</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 query 为 null 时抛出</exception>
public static async Task<TResult> SendQueryAsync<TResult>(this IContextAware contextAware,
IAsyncQuery<TResult> query)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(query);
var context = contextAware.GetContext();
return await context.SendQueryAsync(query);
}
// === 统一请求处理方法 ===
/// <summary>
/// 发送请求(统一处理 Command/Query
/// </summary>
/// <typeparam name="TResponse">响应类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="request">要发送的请求</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>请求结果</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 request 为 null 时抛出</exception>
public static ValueTask<TResponse> SendRequestAsync<TResponse>(this IContextAware contextAware,
IRequest<TResponse> request, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(request);
var context = contextAware.GetContext();
return context.SendRequestAsync(request, cancellationToken);
}
/// <summary>
/// 发送请求(同步版本,不推荐)
/// </summary>
/// <typeparam name="TResponse">响应类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="request">要发送的请求</param>
/// <returns>请求结果</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 request 为 null 时抛出</exception>
public static TResponse SendRequest<TResponse>(this IContextAware contextAware,
IRequest<TResponse> request)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(request);
var context = contextAware.GetContext();
return context.SendRequest(request);
}
/// <summary>
/// 发布通知(一对多事件)
/// </summary>
/// <typeparam name="TNotification">通知类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="notification">要发布的通知</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>异步任务</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 notification 为 null 时抛出</exception>
public static ValueTask PublishAsync<TNotification>(this IContextAware contextAware,
TNotification notification, CancellationToken cancellationToken = default)
where TNotification : INotification
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(notification);
var context = contextAware.GetContext();
return context.PublishAsync(notification, cancellationToken);
}
/// <summary>
/// 创建流式请求(用于大数据集)
/// </summary>
/// <typeparam name="TResponse">响应类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="request">流式请求</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>异步响应流</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 request 为 null 时抛出</exception>
public static IAsyncEnumerable<TResponse> CreateStream<TResponse>(this IContextAware contextAware,
IStreamRequest<TResponse> request, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(request);
var context = contextAware.GetContext();
return context.CreateStream(request, cancellationToken);
}
// === 便捷扩展方法 ===
/// <summary>
/// 发送命令(无返回值)
/// </summary>
/// <typeparam name="TCommand">命令类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="command">要发送的命令</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>异步任务</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static ValueTask SendAsync<TCommand>(this IContextAware contextAware, TCommand command,
CancellationToken cancellationToken = default)
where TCommand : IRequest<Unit>
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(command);
var context = contextAware.GetContext();
return context.SendAsync(command, cancellationToken);
}
/// <summary>
/// 发送命令(有返回值)
/// </summary>
/// <typeparam name="TResponse">响应类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="command">要发送的命令</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>命令执行结果</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 command 为 null 时抛出</exception>
public static ValueTask<TResponse> SendAsync<TResponse>(this IContextAware contextAware,
IRequest<TResponse> command, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(command);
var context = contextAware.GetContext();
return context.SendAsync(command, cancellationToken);
}
/// <summary>
/// 发送查询
/// </summary>
/// <typeparam name="TResponse">响应类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="query">要发送的查询</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>查询结果</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 query 为 null 时抛出</exception>
public static ValueTask<TResponse> QueryAsync<TResponse>(this IContextAware contextAware,
IRequest<TResponse> query, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(query);
var context = contextAware.GetContext();
return context.QueryAsync(query, cancellationToken);
}
/// <summary>
/// 发布事件通知
/// </summary>
/// <typeparam name="TNotification">通知类型</typeparam>
/// <param name="contextAware">实现 IContextAware 接口的对象</param>
/// <param name="notification">要发布的通知</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>异步任务</returns>
/// <exception cref="ArgumentNullException">当 contextAware 或 notification 为 null 时抛出</exception>
public static ValueTask PublishEventAsync<TNotification>(this IContextAware contextAware,
TNotification notification, CancellationToken cancellationToken = default)
where TNotification : INotification
{
ArgumentNullException.ThrowIfNull(contextAware);
ArgumentNullException.ThrowIfNull(notification);
var context = contextAware.GetContext();
return context.PublishEventAsync(notification, cancellationToken);
}
}

View File

@ -1,4 +1,4 @@
using GFramework.Core.Abstractions.architecture;
using GFramework.Core.Abstractions.architecture;
using GFramework.Core.Abstractions.enums;
using GFramework.Core.Abstractions.rule;
using GFramework.Core.Abstractions.state;
@ -87,4 +87,21 @@ public class StateMachineSystem : StateMachine, IStateMachineSystem
NewState = Current
});
}
/// <summary>
/// 异步内部状态切换方法,重写基类方法以添加状态变更事件通知功能
/// </summary>
/// <param name="next">要切换到的下一个状态</param>
protected override async Task ChangeInternalAsync(IState next)
{
var old = Current;
await base.ChangeInternalAsync(next);
// 发送状态变更事件,通知监听者状态已发生改变
this.SendEvent(new StateChangedEvent
{
OldState = old,
NewState = Current
});
}
}