feat(coroutine): 扩展命令协程支持超时等待事件

- 为SendCommandAndWaitEventCoroutine方法添加timeout参数支持
- 实现WaitForEventWithTimeout类用于带超时的事件等待
- 添加泛型约束确保命令类型实现IAsyncCommand接口
- 新增EventListenerScope类提供事件监听器作用域管理
- 支持超时异常处理并抛出相应的TimeoutException
- 优化事件回调处理逻辑,确保事件数据正确传递
This commit is contained in:
GeWuYou 2026-02-01 10:42:34 +08:00
parent a47439f027
commit 9ac4ac0534
2 changed files with 92 additions and 4 deletions

View File

@ -52,10 +52,18 @@ public static class CommandCoroutineExtensions
/// <summary>
/// 发送 Command 并等待指定 Event
/// </summary>
/// <typeparam name="TCommand">命令类型,必须实现 IAsyncCommand 接口</typeparam>
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="contextAware">上下文感知对象</param>
/// <param name="command">要执行的命令实例</param>
/// <param name="onEvent">事件触发时的回调处理</param>
/// <param name="timeout">等待超时时间0表示无限等待</param>
/// <returns>返回协程指令枚举器</returns>
public static IEnumerator<IYieldInstruction> SendCommandAndWaitEventCoroutine<TCommand, TEvent>(
this IContextAware contextAware,
TCommand command,
Action<TEvent>? onEvent = null)
Action<TEvent>? onEvent = null,
float timeout = 0f)
where TCommand : IAsyncCommand
where TEvent : class
{
@ -73,10 +81,26 @@ public static class CommandCoroutineExtensions
var task = context.SendCommandAsync(command);
yield return task.AsCoroutineInstruction();
// 等待事件触发
yield return wait;
// 如果有超时设置,使用超时等待
if (timeout > 0f)
{
var timeoutWait = new WaitForEventWithTimeout<TEvent>(wait, timeout);
yield return timeoutWait;
// 调用回调
// 检查是否超时
if (timeoutWait.IsTimeout)
{
// 超时处理
throw new TimeoutException($"wait for the event ${typeof(TEvent).Name} timeout.");
}
}
else
{
// 等待事件触发(无超时)
yield return wait;
}
// 调用事件回调
if (onEvent != null && wait.EventData != null)
{
onEvent.Invoke(wait.EventData);

View File

@ -0,0 +1,64 @@
// Copyright (c) 2026 GeWuYou
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using GFramework.Core.Abstractions.events;
namespace GFramework.Core.events;
/// <summary>
/// 事件监听器作用域,用于监听特定类型的事件并在触发时提供事件数据
/// </summary>
/// <typeparam name="TEvent">要监听的事件类型</typeparam>
public sealed class EventListenerScope<TEvent> : IDisposable
{
private readonly IUnRegister? _unRegister;
private TEvent? _eventData;
private volatile bool _triggered;
/// <summary>
/// 初始化事件监听器作用域的新实例
/// </summary>
/// <param name="eventBus">事件总线实例,用于注册事件监听器</param>
public EventListenerScope(IEventBus eventBus)
{
_unRegister = eventBus.Register<TEvent>(OnEventTriggered);
}
/// <summary>
/// 获取接收到的事件数据
/// </summary>
public TEvent? EventData => _eventData;
/// <summary>
/// 获取事件是否已被触发
/// </summary>
public bool IsTriggered => _triggered;
/// <summary>
/// 释放资源,取消事件监听器的注册
/// </summary>
public void Dispose()
{
_unRegister?.UnRegister();
}
/// <summary>
/// 事件触发时的回调方法,用于存储事件数据并标记已触发状态
/// </summary>
/// <param name="eventData">接收到的事件数据</param>
private void OnEventTriggered(TEvent eventData)
{
_eventData = eventData;
_triggered = true;
}
}