From 32be23b01dd3920144e6ea015263da383e88c941 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Sun, 1 Feb 2026 10:35:11 +0800 Subject: [PATCH] =?UTF-8?q?feat(coroutine):=20=E6=B7=BB=E5=8A=A0=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E5=92=8C=E6=9F=A5=E8=AF=A2=E7=9A=84=E5=8D=8F=E7=A8=8B?= =?UTF-8?q?=E6=89=A9=E5=B1=95=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现了 CommandCoroutineExtensions 类,提供命令异步执行的协程包装 - 添加了 SendCommandCoroutineWithErrorHandler 方法处理命令执行异常 - 实现了 SendCommandAndWaitEventCoroutine 方法支持发送命令并等待事件 - 创建了 QueryCoroutineExtensions 类,提供查询操作的协程扩展 - 添加了 WaitForEvent 协程指令用于等待特定事件触发 - 实现了完整的事件监听和资源清理机制 --- .../extensions/CommandCoroutineExtensions.cs | 91 +++++++++++++++++++ .../extensions/QueryCoroutineExtensions.cs | 50 ++++++++++ .../coroutine/instructions/WaitForEvent.cs | 83 +++++++++++++++++ 3 files changed, 224 insertions(+) create mode 100644 GFramework.Core/coroutine/extensions/CommandCoroutineExtensions.cs create mode 100644 GFramework.Core/coroutine/extensions/QueryCoroutineExtensions.cs create mode 100644 GFramework.Core/coroutine/instructions/WaitForEvent.cs diff --git a/GFramework.Core/coroutine/extensions/CommandCoroutineExtensions.cs b/GFramework.Core/coroutine/extensions/CommandCoroutineExtensions.cs new file mode 100644 index 0000000..817b8c3 --- /dev/null +++ b/GFramework.Core/coroutine/extensions/CommandCoroutineExtensions.cs @@ -0,0 +1,91 @@ +// 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.command; +using GFramework.Core.Abstractions.coroutine; +using GFramework.Core.Abstractions.events; +using GFramework.Core.Abstractions.rule; +using GFramework.Core.coroutine.instructions; + +namespace GFramework.Core.coroutine.extensions; + +/// +/// 命令协程扩展方法类 +/// 提供将命令的异步执行包装为协程的功能 +/// +public static class CommandCoroutineExtensions +{ + /// + /// 将 Command 的异步执行包装为协程,并处理异常 + /// + /// 命令类型,必须实现 IAsyncCommand 接口 + /// 上下文感知对象 + /// 要执行的命令实例 + /// 错误回调处理 + /// 返回协程指令枚举器 + public static IEnumerator SendCommandCoroutineWithErrorHandler( + this IContextAware contextAware, + TCommand command, + Action? onError) + where TCommand : class, IAsyncCommand + { + var task = contextAware.GetContext().SendCommandAsync(command); + + yield return task.AsCoroutineInstruction(); + + if (task.IsFaulted) + { + onError?.Invoke(task.Exception!); + } + } + + /// + /// 发送 Command 并等待指定 Event + /// + public static IEnumerator SendCommandAndWaitEventCoroutine( + this IContextAware contextAware, + TCommand command, + Action? onEvent = null) + where TCommand : IAsyncCommand + where TEvent : class + { + var context = contextAware.GetContext(); + var eventBus = context.GetService()!; + + WaitForEvent? wait = null; + + try + { + // 先注册事件监听器 + wait = new WaitForEvent(eventBus); + + // 发送异步命令并等待完成 + var task = context.SendCommandAsync(command); + yield return task.AsCoroutineInstruction(); + + // 等待事件触发 + yield return wait; + + // 调用回调 + if (onEvent != null && wait.EventData != null) + { + onEvent.Invoke(wait.EventData); + } + } + finally + { + // 确保清理事件监听器 + wait?.Dispose(); + } + } +} \ No newline at end of file diff --git a/GFramework.Core/coroutine/extensions/QueryCoroutineExtensions.cs b/GFramework.Core/coroutine/extensions/QueryCoroutineExtensions.cs new file mode 100644 index 0000000..27f12dd --- /dev/null +++ b/GFramework.Core/coroutine/extensions/QueryCoroutineExtensions.cs @@ -0,0 +1,50 @@ +// 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.query; +using GFramework.Core.Abstractions.rule; + +namespace GFramework.Core.coroutine.extensions; + +/// +/// 查询协程扩展方法类 +/// 提供将查询操作包装为协程的扩展方法 +/// +public static class QueryCoroutineExtensions +{ + /// + /// 将 Query 包装为协程(立即返回结果) + /// + /// 查询类型,必须实现 IQuery<TResult> 接口 + /// 查询结果类型 + /// 上下文感知对象,用于获取执行上下文 + /// 要执行的查询对象 + /// 处理查询结果的回调方法 + /// 返回一个协程迭代器,立即执行并返回结果 + public static IEnumerator SendQueryCoroutine( + this IContextAware contextAware, + TQuery query, + Action onResult) + where TQuery : IQuery + { + // 执行查询并获取结果 + var result = contextAware.GetContext().SendQuery(query); + + // 调用结果处理回调 + onResult(result); + + // 协程立即结束 + yield break; + } +} \ No newline at end of file diff --git a/GFramework.Core/coroutine/instructions/WaitForEvent.cs b/GFramework.Core/coroutine/instructions/WaitForEvent.cs new file mode 100644 index 0000000..b267c0a --- /dev/null +++ b/GFramework.Core/coroutine/instructions/WaitForEvent.cs @@ -0,0 +1,83 @@ +// 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; + +namespace GFramework.Core.coroutine.instructions; + +public sealed class WaitForEvent : IYieldInstruction, IDisposable +{ + private bool _disposed; + private volatile bool _done; + private TEvent? _eventData; + private IUnRegister? _unRegister; + + /// + /// 初始化等待事件的指令 + /// + /// 事件总线实例 + public WaitForEvent(IEventBus eventBus) + { + var eventBus1 = eventBus ?? throw new ArgumentNullException(nameof(eventBus)); + + // 注册事件监听器 + _unRegister = eventBus1.Register(OnEventTriggered); + } + + /// + /// 获取接收到的事件数据 + /// + public TEvent? EventData => _eventData; + + /// + /// 释放资源 + /// + public void Dispose() + { + if (_disposed) return; + + // 注销事件注册并清理资源 + _unRegister?.UnRegister(); + _unRegister = null; + _disposed = true; + } + + /// + /// 获取等待是否已完成 + /// + public bool IsDone => _done; + + /// + /// 更新方法,用于处理时间更新逻辑 + /// + /// 时间增量 + public void Update(double deltaTime) + { + // 事件的完成由事件回调设置 + // 如果已完成,确保注销事件监听器 + if (!_done || _unRegister == null) return; + _unRegister.UnRegister(); + _unRegister = null; + } + + /// + /// 事件触发时的回调处理 + /// + /// 事件数据 + private void OnEventTriggered(TEvent eventData) + { + _eventData = eventData; + _done = true; + } +} \ No newline at end of file