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(); 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> /// <summary>
/// 发送 Command 并等待指定 Event /// 发送 Command 并等待指定 Event
/// </summary> /// </summary>
/// <typeparam name="TCommand">命令类型,必须实现 IAsyncCommand 接口</typeparam> /// <typeparam name="TCommand">命令类型,必须实现 IAsyncCommand</typeparam>
/// <typeparam name="TEvent">事件类型</typeparam> /// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="contextAware">上下文感知对象</param> /// <param name="contextAware">上下文感知对象</param>
/// <param name="command">要执行的命令实例</param> /// <param name="command">要执行的命令实例</param>
/// <param name="onEvent">事件触发时的回调处理</param> /// <param name="onEvent">事件触发时的回调处理</param>
/// <param name="timeout">等待超时时间0表示无限等待</param> /// <param name="timeout">
/// <returns>返回协程指令枚举器</returns> /// 超时时间(秒):
/// <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>( public static IEnumerator<IYieldInstruction> SendCommandAndWaitEventCoroutine<TCommand, TEvent>(
this IContextAware contextAware, this IContextAware contextAware,
TCommand command, TCommand command,
@ -63,44 +74,64 @@ public static class CommandCoroutineExtensions
float timeout = 0f) float timeout = 0f)
where TCommand : IAsyncCommand where TCommand : IAsyncCommand
where TEvent : class 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 context = contextAware.GetContext();
var eventBus = context.GetService<IEventBus>()!; var eventBus = context.GetService<IEventBus>()
?? throw new InvalidOperationException("IEventBus not found.");
WaitForEvent<TEvent>? wait = null; WaitForEvent<TEvent>? wait = null;
try try
{ {
// 先注册事件监听器 // 先注册事件监听
wait = new WaitForEvent<TEvent>(eventBus); wait = new WaitForEvent<TEvent>(eventBus);
// 发送异步命令并等待完成 // 发送命令
var task = context.SendCommandAsync(command); var task = context.SendCommandAsync(command);
yield return task.AsCoroutineInstruction(); yield return task.AsCoroutineInstruction();
// 如果有超时设置,使用超时等待 // 等待事件
if (timeout > 0f) if (timeout > 0f)
{ {
var timeoutWait = new WaitForEventWithTimeout<TEvent>(wait, timeout); var timeoutWait = new WaitForEventWithTimeout<TEvent>(wait, timeout);
yield return timeoutWait; yield return timeoutWait;
// 检查是否超时
if (timeoutWait.IsTimeout) if (timeoutWait.IsTimeout)
// 超时处理 throw new TimeoutException(
throw new TimeoutException($"wait for the event ${typeof(TEvent).Name} timeout."); $"Wait for event {typeof(TEvent).Name} timeout.");
} }
else else
{ {
// 等待事件触发(无超时)
yield return wait; yield return wait;
} }
// 调用事件回调 if (wait.EventData != null)
if (onEvent != null && wait.EventData != null) onEvent.Invoke(wait.EventData); onEvent?.Invoke(wait.EventData);
} }
finally finally
{ {
// 确保清理事件监听器
wait?.Dispose(); 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"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
// You may obtain a copy of the License at // You may obtain a copy of the License at
@ -47,20 +47,31 @@ public static class MediatorCoroutineExtensions
yield return task.AsCoroutineInstruction(); yield return task.AsCoroutineInstruction();
if (task.IsFaulted) if (!task.IsFaulted) yield break;
onError?.Invoke(task.Exception!); if (onError != null)
onError.Invoke(task.Exception!);
else
throw task.Exception!.InnerException ?? task.Exception;
} }
// ... existing code ...
/// <summary> /// <summary>
/// 发送命令并等待特定事件的协程实现,支持超时控制 /// 发送命令并等待特定事件的协程实现
/// </summary> /// </summary>
/// <typeparam name="TCommand">命令类型</typeparam> /// <typeparam name="TCommand">命令类型</typeparam>
/// <typeparam name="TEvent">要等待的事件类型</typeparam> /// <typeparam name="TEvent">要等待的事件类型</typeparam>
/// <param name="contextAware">上下文感知对象,用于获取服务</param> /// <param name="contextAware">上下文对象</param>
/// <param name="command">要发送的命令对象</param> /// <param name="command">要发送的命令</param>
/// <param name="onEvent">接收到事件时的回调处理函数</param> /// <param name="onEvent">事件触发时的回调</param>
/// <param name="timeout">超时时间0表示无超时</param> /// <param name="timeout">
/// <returns>协程枚举器,用于协程执行</returns> /// 超时时间(秒):
/// <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>( public static IEnumerator<IYieldInstruction> SendCommandAndWaitEventCoroutine<TCommand, TEvent>(
this IContextAware contextAware, this IContextAware contextAware,
TCommand command, TCommand command,
@ -69,10 +80,54 @@ public static class MediatorCoroutineExtensions
where TCommand : notnull where TCommand : notnull
where TEvent : class where TEvent : class
{ {
var context = contextAware.GetContext(); // 参数验证
var mediator = context.GetService<IMediator>()!; ValidateParameters(timeout);
var eventBus = context.GetService<IEventBus>()!;
// 获取必要的服务
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; WaitForEvent<TEvent>? wait = null;
try try
@ -80,7 +135,6 @@ public static class MediatorCoroutineExtensions
wait = new WaitForEvent<TEvent>(eventBus); wait = new WaitForEvent<TEvent>(eventBus);
var task = mediator.Send(command).AsTask(); var task = mediator.Send(command).AsTask();
yield return task.AsCoroutineInstruction(); yield return task.AsCoroutineInstruction();
if (timeout > 0f) if (timeout > 0f)
@ -90,7 +144,7 @@ public static class MediatorCoroutineExtensions
if (timeoutWait.IsTimeout) if (timeoutWait.IsTimeout)
throw new TimeoutException( throw new TimeoutException(
$"wait for event {typeof(TEvent).Name} timeout."); $"Wait for event {typeof(TEvent).Name} timeout.");
} }
else else
{ {
@ -105,4 +159,5 @@ public static class MediatorCoroutineExtensions
wait?.Dispose(); wait?.Dispose();
} }
} }
// ... existing code ...
} }