refactor(coroutine): 优化协程扩展中的异常处理和参数验证

- 修改了CommandCoroutineExtensions和MediatorCoroutineExtensions中的异常处理逻辑
- 添加了对负数超时参数的验证和异常抛出
- 改进了服务获取的空值检查机制
- 更新了文档注释以提供更清晰的参数说明
- 重构了SendCommandAndWaitEvent方法的实现结构
- 统一了错误消息格式和异常处理方式
This commit is contained in:
GeWuYou 2026-02-16 22:19:12 +08:00 committed by gewuyou
parent b196cd40bb
commit 855b3f9eac
2 changed files with 117 additions and 31 deletions

View File

@ -43,19 +43,30 @@ public static class CommandCoroutineExtensions
yield return task.AsCoroutineInstruction();
if (task.IsFaulted) onError?.Invoke(task.Exception!);
if (!task.IsFaulted) yield break;
if (onError != null)
onError.Invoke(task.Exception!);
else
throw task.Exception!.InnerException ?? task.Exception;
}
/// <summary>
/// 发送 Command 并等待指定 Event
/// 发送 Command 并等待指定 Event
/// </summary>
/// <typeparam name="TCommand">命令类型,必须实现 IAsyncCommand 接口</typeparam>
/// <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>
/// <param name="timeout">
/// 超时时间(秒):
/// <list type="bullet">
/// <item><description>timeout &lt; 0: 无效,将抛出 ArgumentOutOfRangeException</description></item>
/// <item><description>timeout == 0: 无超时,永久等待</description></item>
/// <item><description>timeout &gt; 0: 启用超时机制</description></item>
/// </list>
/// </param>
/// <exception cref="ArgumentOutOfRangeException">当 timeout 小于 0 时抛出。</exception>
public static IEnumerator<IYieldInstruction> SendCommandAndWaitEventCoroutine<TCommand, TEvent>(
this IContextAware contextAware,
TCommand command,
@ -63,44 +74,64 @@ public static class CommandCoroutineExtensions
float timeout = 0f)
where TCommand : IAsyncCommand
where TEvent : class
{
// 参数检查部分
if (timeout < 0f)
throw new ArgumentOutOfRangeException(
nameof(timeout),
timeout,
"Timeout must be greater than or equal to 0.");
// 迭代器逻辑部分
return SendCommandAndWaitEventIterator(contextAware, command, onEvent, timeout);
}
/// <summary>
/// 发送 Command 并等待指定 Event 的迭代器实现。
/// </summary>
private static IEnumerator<IYieldInstruction> SendCommandAndWaitEventIterator<TCommand, TEvent>(
IContextAware contextAware,
TCommand command,
Action<TEvent>? onEvent,
float timeout)
where TCommand : IAsyncCommand
where TEvent : class
{
var context = contextAware.GetContext();
var eventBus = context.GetService<IEventBus>()!;
var eventBus = context.GetService<IEventBus>()
?? throw new InvalidOperationException("IEventBus not found.");
WaitForEvent<TEvent>? wait = null;
try
{
// 先注册事件监听器
// 先注册事件监听
wait = new WaitForEvent<TEvent>(eventBus);
// 发送异步命令并等待完成
// 发送命令
var task = context.SendCommandAsync(command);
yield return task.AsCoroutineInstruction();
// 如果有超时设置,使用超时等待
// 等待事件
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.");
throw new TimeoutException(
$"Wait for event {typeof(TEvent).Name} timeout.");
}
else
{
// 等待事件触发(无超时)
yield return wait;
}
// 调用事件回调
if (onEvent != null && wait.EventData != null) onEvent.Invoke(wait.EventData);
if (wait.EventData != null)
onEvent?.Invoke(wait.EventData);
}
finally
{
// 确保清理事件监听器
wait?.Dispose();
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2026 GeWuYou
// 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
@ -47,20 +47,31 @@ public static class MediatorCoroutineExtensions
yield return task.AsCoroutineInstruction();
if (task.IsFaulted)
onError?.Invoke(task.Exception!);
if (!task.IsFaulted) yield break;
if (onError != null)
onError.Invoke(task.Exception!);
else
throw task.Exception!.InnerException ?? task.Exception;
}
// ... existing code ...
/// <summary>
/// 发送命令并等待特定事件的协程实现,支持超时控制
/// 发送命令并等待特定事件的协程实现
/// </summary>
/// <typeparam name="TCommand">命令类型</typeparam>
/// <typeparam name="TCommand">命令类型</typeparam>
/// <typeparam name="TEvent">要等待的事件类型</typeparam>
/// <param name="contextAware">上下文感知对象,用于获取服务</param>
/// <param name="command">要发送的命令对象</param>
/// <param name="onEvent">接收到事件时的回调处理函数</param>
/// <param name="timeout">超时时间0表示无超时</param>
/// <returns>协程枚举器,用于协程执行</returns>
/// <param name="contextAware">上下文对象</param>
/// <param name="command">要发送的命令</param>
/// <param name="onEvent">事件触发时的回调</param>
/// <param name="timeout">
/// 超时时间(秒):
/// <list type="bullet">
/// <item><description>timeout &lt; 0: 无效,将抛出 ArgumentOutOfRangeException</description></item>
/// <item><description>timeout == 0: 无超时,永久等待</description></item>
/// <item><description>timeout &gt; 0: 启用超时机制</description></item>
/// </list>
/// </param>
/// <exception cref="ArgumentOutOfRangeException">当 timeout 小于 0 时抛出。</exception>
public static IEnumerator<IYieldInstruction> SendCommandAndWaitEventCoroutine<TCommand, TEvent>(
this IContextAware contextAware,
TCommand command,
@ -69,10 +80,54 @@ public static class MediatorCoroutineExtensions
where TCommand : notnull
where TEvent : class
{
var context = contextAware.GetContext();
var mediator = context.GetService<IMediator>()!;
var eventBus = context.GetService<IEventBus>()!;
// 参数验证
ValidateParameters(timeout);
// 获取必要的服务
var context = contextAware.GetContext();
var mediator = context.GetService<IMediator>()
?? throw new InvalidOperationException("IMediator not found.");
var eventBus = context.GetService<IEventBus>()
?? throw new InvalidOperationException("IEventBus not found.");
// 执行协程逻辑
return ExecuteSendCommandAndWaitEventCoroutine(mediator, eventBus, command, onEvent, timeout);
}
/// <summary>
/// 验证方法参数的有效性。
/// </summary>
/// <param name="timeout">超时时间</param>
/// <exception cref="ArgumentOutOfRangeException">当 timeout 小于 0 时抛出。</exception>
private static void ValidateParameters(float timeout)
{
if (timeout < 0f)
throw new ArgumentOutOfRangeException(
nameof(timeout),
timeout,
"Timeout must be greater than or equal to 0.");
}
/// <summary>
/// 执行发送命令并等待事件的协程逻辑。
/// </summary>
/// <typeparam name="TCommand">命令类型</typeparam>
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="mediator">中介者服务</param>
/// <param name="eventBus">事件总线服务</param>
/// <param name="command">要发送的命令</param>
/// <param name="onEvent">事件回调</param>
/// <param name="timeout">超时时间</param>
/// <returns>协程枚举器</returns>
private static IEnumerator<IYieldInstruction> ExecuteSendCommandAndWaitEventCoroutine<TCommand, TEvent>(
IMediator mediator,
IEventBus eventBus,
TCommand command,
Action<TEvent>? onEvent,
float timeout)
where TCommand : notnull
where TEvent : class
{
WaitForEvent<TEvent>? wait = null;
try
@ -80,7 +135,6 @@ public static class MediatorCoroutineExtensions
wait = new WaitForEvent<TEvent>(eventBus);
var task = mediator.Send(command).AsTask();
yield return task.AsCoroutineInstruction();
if (timeout > 0f)
@ -90,7 +144,7 @@ public static class MediatorCoroutineExtensions
if (timeoutWait.IsTimeout)
throw new TimeoutException(
$"wait for event {typeof(TEvent).Name} timeout.");
$"Wait for event {typeof(TEvent).Name} timeout.");
}
else
{
@ -105,4 +159,5 @@ public static class MediatorCoroutineExtensions
wait?.Dispose();
}
}
// ... existing code ...
}