diff --git a/GFramework.Core/coroutine/extensions/CommandCoroutineExtensions.cs b/GFramework.Core/coroutine/extensions/CommandCoroutineExtensions.cs index a919458..62183ca 100644 --- a/GFramework.Core/coroutine/extensions/CommandCoroutineExtensions.cs +++ b/GFramework.Core/coroutine/extensions/CommandCoroutineExtensions.cs @@ -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; } /// - /// 发送 Command 并等待指定 Event + /// 发送 Command 并等待指定 Event。 /// - /// 命令类型,必须实现 IAsyncCommand 接口 + /// 命令类型,必须实现 IAsyncCommand /// 事件类型 /// 上下文感知对象 /// 要执行的命令实例 /// 事件触发时的回调处理 - /// 等待超时时间(秒),0表示无限等待 - /// 返回协程指令枚举器 + /// + /// 超时时间(秒): + /// + /// timeout < 0: 无效,将抛出 ArgumentOutOfRangeException + /// timeout == 0: 无超时,永久等待 + /// timeout > 0: 启用超时机制 + /// + /// + /// 当 timeout 小于 0 时抛出。 public static IEnumerator SendCommandAndWaitEventCoroutine( 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); + } + + /// + /// 发送 Command 并等待指定 Event 的迭代器实现。 + /// + private static IEnumerator SendCommandAndWaitEventIterator( + IContextAware contextAware, + TCommand command, + Action? onEvent, + float timeout) + where TCommand : IAsyncCommand + where TEvent : class { var context = contextAware.GetContext(); - var eventBus = context.GetService()!; + var eventBus = context.GetService() + ?? throw new InvalidOperationException("IEventBus not found."); WaitForEvent? wait = null; try { - // 先注册事件监听器 + // 先注册事件监听 wait = new WaitForEvent(eventBus); - // 发送异步命令并等待完成 + // 发送命令 var task = context.SendCommandAsync(command); yield return task.AsCoroutineInstruction(); - // 如果有超时设置,使用超时等待 + // 等待事件 if (timeout > 0f) { var timeoutWait = new WaitForEventWithTimeout(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(); } } diff --git a/GFramework.Core/coroutine/extensions/MediatorCoroutineExtensions.cs b/GFramework.Core/coroutine/extensions/MediatorCoroutineExtensions.cs index 046964f..edbf02a 100644 --- a/GFramework.Core/coroutine/extensions/MediatorCoroutineExtensions.cs +++ b/GFramework.Core/coroutine/extensions/MediatorCoroutineExtensions.cs @@ -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 ... /// - /// 发送命令并等待特定事件的协程实现,支持超时控制。 + /// 发送命令并等待特定事件的协程实现。 /// - /// 命令的类型 + /// 命令类型 /// 要等待的事件类型 - /// 上下文感知对象,用于获取服务 - /// 要发送的命令对象 - /// 接收到事件时的回调处理函数 - /// 超时时间(秒),0表示无超时 - /// 协程枚举器,用于协程执行 + /// 上下文对象 + /// 要发送的命令 + /// 事件触发时的回调 + /// + /// 超时时间(秒): + /// + /// timeout < 0: 无效,将抛出 ArgumentOutOfRangeException + /// timeout == 0: 无超时,永久等待 + /// timeout > 0: 启用超时机制 + /// + /// + /// 当 timeout 小于 0 时抛出。 public static IEnumerator SendCommandAndWaitEventCoroutine( 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()!; - var eventBus = context.GetService()!; + // 参数验证 + ValidateParameters(timeout); + // 获取必要的服务 + var context = contextAware.GetContext(); + var mediator = context.GetService() + ?? throw new InvalidOperationException("IMediator not found."); + var eventBus = context.GetService() + ?? throw new InvalidOperationException("IEventBus not found."); + + // 执行协程逻辑 + return ExecuteSendCommandAndWaitEventCoroutine(mediator, eventBus, command, onEvent, timeout); + } + + /// + /// 验证方法参数的有效性。 + /// + /// 超时时间 + /// 当 timeout 小于 0 时抛出。 + private static void ValidateParameters(float timeout) + { + if (timeout < 0f) + throw new ArgumentOutOfRangeException( + nameof(timeout), + timeout, + "Timeout must be greater than or equal to 0."); + } + + /// + /// 执行发送命令并等待事件的协程逻辑。 + /// + /// 命令类型 + /// 事件类型 + /// 中介者服务 + /// 事件总线服务 + /// 要发送的命令 + /// 事件回调 + /// 超时时间 + /// 协程枚举器 + private static IEnumerator ExecuteSendCommandAndWaitEventCoroutine( + IMediator mediator, + IEventBus eventBus, + TCommand command, + Action? onEvent, + float timeout) + where TCommand : notnull + where TEvent : class + { WaitForEvent? wait = null; try @@ -80,7 +135,6 @@ public static class MediatorCoroutineExtensions wait = new WaitForEvent(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 ... } \ No newline at end of file