diff --git a/GFramework.Core/coroutine/extensions/MediatorCoroutineExtensions.cs b/GFramework.Core/coroutine/extensions/MediatorCoroutineExtensions.cs new file mode 100644 index 0000000..046964f --- /dev/null +++ b/GFramework.Core/coroutine/extensions/MediatorCoroutineExtensions.cs @@ -0,0 +1,108 @@ +// 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.coroutine; +using GFramework.Core.Abstractions.events; +using GFramework.Core.Abstractions.rule; +using GFramework.Core.coroutine.instructions; +using Mediator; + +namespace GFramework.Core.coroutine.extensions; + +/// +/// 提供Mediator模式与协程集成的扩展方法。 +/// 包含发送命令和等待事件的协程实现。 +/// +public static class MediatorCoroutineExtensions +{ + /// + /// 以协程方式发送命令并处理可能的异常。 + /// + /// 命令的类型 + /// 上下文感知对象,用于获取服务 + /// 要发送的命令对象 + /// 发生异常时的回调处理函数 + /// 协程枚举器,用于协程执行 + public static IEnumerator SendCommandCoroutine( + this IContextAware contextAware, + TCommand command, + Action? onError = null) + where TCommand : notnull + { + var mediator = contextAware + .GetContext() + .GetService()!; + + var task = mediator.Send(command).AsTask(); + + yield return task.AsCoroutineInstruction(); + + if (task.IsFaulted) + onError?.Invoke(task.Exception!); + } + + /// + /// 发送命令并等待特定事件的协程实现,支持超时控制。 + /// + /// 命令的类型 + /// 要等待的事件类型 + /// 上下文感知对象,用于获取服务 + /// 要发送的命令对象 + /// 接收到事件时的回调处理函数 + /// 超时时间(秒),0表示无超时 + /// 协程枚举器,用于协程执行 + public static IEnumerator SendCommandAndWaitEventCoroutine( + this IContextAware contextAware, + TCommand command, + Action? onEvent = null, + float timeout = 0f) + where TCommand : notnull + where TEvent : class + { + var context = contextAware.GetContext(); + var mediator = context.GetService()!; + var eventBus = context.GetService()!; + + WaitForEvent? wait = null; + + try + { + wait = new WaitForEvent(eventBus); + + var task = mediator.Send(command).AsTask(); + + yield return task.AsCoroutineInstruction(); + + if (timeout > 0f) + { + var timeoutWait = new WaitForEventWithTimeout(wait, timeout); + yield return timeoutWait; + + if (timeoutWait.IsTimeout) + throw new TimeoutException( + $"wait for event {typeof(TEvent).Name} timeout."); + } + else + { + yield return wait; + } + + if (wait.EventData != null) + onEvent?.Invoke(wait.EventData); + } + finally + { + wait?.Dispose(); + } + } +} \ No newline at end of file