feat(coroutine): 添加命令和查询的协程扩展功能

- 实现了 CommandCoroutineExtensions 类,提供命令异步执行的协程包装
- 添加了 SendCommandCoroutineWithErrorHandler 方法处理命令执行异常
- 实现了 SendCommandAndWaitEventCoroutine 方法支持发送命令并等待事件
- 创建了 QueryCoroutineExtensions 类,提供查询操作的协程扩展
- 添加了 WaitForEvent 协程指令用于等待特定事件触发
- 实现了完整的事件监听和资源清理机制
This commit is contained in:
GeWuYou 2026-02-01 10:35:11 +08:00
parent af64c4ab3e
commit 32be23b01d
3 changed files with 224 additions and 0 deletions

View File

@ -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;
/// <summary>
/// 命令协程扩展方法类
/// 提供将命令的异步执行包装为协程的功能
/// </summary>
public static class CommandCoroutineExtensions
{
/// <summary>
/// 将 Command 的异步执行包装为协程,并处理异常
/// </summary>
/// <typeparam name="TCommand">命令类型,必须实现 IAsyncCommand 接口</typeparam>
/// <param name="contextAware">上下文感知对象</param>
/// <param name="command">要执行的命令实例</param>
/// <param name="onError">错误回调处理</param>
/// <returns>返回协程指令枚举器</returns>
public static IEnumerator<IYieldInstruction> SendCommandCoroutineWithErrorHandler<TCommand>(
this IContextAware contextAware,
TCommand command,
Action<Exception>? onError)
where TCommand : class, IAsyncCommand
{
var task = contextAware.GetContext().SendCommandAsync(command);
yield return task.AsCoroutineInstruction();
if (task.IsFaulted)
{
onError?.Invoke(task.Exception!);
}
}
/// <summary>
/// 发送 Command 并等待指定 Event
/// </summary>
public static IEnumerator<IYieldInstruction> SendCommandAndWaitEventCoroutine<TCommand, TEvent>(
this IContextAware contextAware,
TCommand command,
Action<TEvent>? onEvent = null)
where TCommand : IAsyncCommand
where TEvent : class
{
var context = contextAware.GetContext();
var eventBus = context.GetService<IEventBus>()!;
WaitForEvent<TEvent>? wait = null;
try
{
// 先注册事件监听器
wait = new WaitForEvent<TEvent>(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();
}
}
}

View File

@ -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;
/// <summary>
/// 查询协程扩展方法类
/// 提供将查询操作包装为协程的扩展方法
/// </summary>
public static class QueryCoroutineExtensions
{
/// <summary>
/// 将 Query 包装为协程(立即返回结果)
/// </summary>
/// <typeparam name="TQuery">查询类型,必须实现 IQuery&lt;TResult&gt; 接口</typeparam>
/// <typeparam name="TResult">查询结果类型</typeparam>
/// <param name="contextAware">上下文感知对象,用于获取执行上下文</param>
/// <param name="query">要执行的查询对象</param>
/// <param name="onResult">处理查询结果的回调方法</param>
/// <returns>返回一个协程迭代器,立即执行并返回结果</returns>
public static IEnumerator<IYieldInstruction> SendQueryCoroutine<TQuery, TResult>(
this IContextAware contextAware,
TQuery query,
Action<TResult> onResult)
where TQuery : IQuery<TResult>
{
// 执行查询并获取结果
var result = contextAware.GetContext().SendQuery(query);
// 调用结果处理回调
onResult(result);
// 协程立即结束
yield break;
}
}

View File

@ -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<TEvent> : IYieldInstruction, IDisposable
{
private bool _disposed;
private volatile bool _done;
private TEvent? _eventData;
private IUnRegister? _unRegister;
/// <summary>
/// 初始化等待事件的指令
/// </summary>
/// <param name="eventBus">事件总线实例</param>
public WaitForEvent(IEventBus eventBus)
{
var eventBus1 = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
// 注册事件监听器
_unRegister = eventBus1.Register<TEvent>(OnEventTriggered);
}
/// <summary>
/// 获取接收到的事件数据
/// </summary>
public TEvent? EventData => _eventData;
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
if (_disposed) return;
// 注销事件注册并清理资源
_unRegister?.UnRegister();
_unRegister = null;
_disposed = true;
}
/// <summary>
/// 获取等待是否已完成
/// </summary>
public bool IsDone => _done;
/// <summary>
/// 更新方法,用于处理时间更新逻辑
/// </summary>
/// <param name="deltaTime">时间增量</param>
public void Update(double deltaTime)
{
// 事件的完成由事件回调设置
// 如果已完成,确保注销事件监听器
if (!_done || _unRegister == null) return;
_unRegister.UnRegister();
_unRegister = null;
}
/// <summary>
/// 事件触发时的回调处理
/// </summary>
/// <param name="eventData">事件数据</param>
private void OnEventTriggered(TEvent eventData)
{
_eventData = eventData;
_done = true;
}
}