From 45ab38519b0701d65db99b820fdbfb173ffe3f04 Mon Sep 17 00:00:00 2001
From: GeWuYou <95328647+GeWuYou@users.noreply.github.com>
Date: Fri, 17 Apr 2026 18:12:18 +0800
Subject: [PATCH] =?UTF-8?q?feat(cqrs):=20=E6=B7=BB=E5=8A=A0CQRS=E8=BF=90?=
=?UTF-8?q?=E8=A1=8C=E6=97=B6=E5=AE=9E=E7=8E=B0=E5=92=8C=E4=B8=AD=E6=96=87?=
=?UTF-8?q?=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 实现了完整的CQRS分发器,支持命令、查询、通知和流式处理
- 添加了弱键缓存机制确保程序集卸载安全
- 实现了管道行为支持,可添加日志、验证等横切关注点
- 提供了类型安全的请求分发和处理器注册功能
- 编写了详细的CQRS中文文档,涵盖基本用法和最佳实践
- 支持编译期生成处理器注册表优化启动性能
---
GFramework.Cqrs/Internal/CqrsDispatcher.cs | 37 ++++++++++++++++++++++
GFramework.Cqrs/Internal/WeakKeyCache.cs | 36 ++++++++++++++++++++-
docs/zh-CN/core/cqrs.md | 1 +
3 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/GFramework.Cqrs/Internal/CqrsDispatcher.cs b/GFramework.Cqrs/Internal/CqrsDispatcher.cs
index d229d190..5f7fa643 100644
--- a/GFramework.Cqrs/Internal/CqrsDispatcher.cs
+++ b/GFramework.Cqrs/Internal/CqrsDispatcher.cs
@@ -387,32 +387,69 @@ internal sealed class CqrsDispatcher(
}
}
+ ///
+ /// 保存通知分发路径所需的服务类型与强类型调用委托。
+ /// 该绑定把“容器解析哪个服务类型”与“如何调用处理器”聚合到同一缓存项中。
+ ///
private sealed class NotificationDispatchBinding(Type handlerType, NotificationInvoker invoker)
{
+ ///
+ /// 获取通知处理器在容器中的服务类型。
+ ///
public Type HandlerType { get; } = handlerType;
+ ///
+ /// 获取执行通知处理器的强类型调用委托。
+ ///
public NotificationInvoker Invoker { get; } = invoker;
}
+ ///
+ /// 保存流式请求分发路径所需的服务类型与调用委托。
+ /// 该绑定让建流热路径只需一次缓存命中即可获得解析与调用所需元数据。
+ ///
private sealed class StreamDispatchBinding(Type handlerType, StreamInvoker invoker)
{
+ ///
+ /// 获取流式请求处理器在容器中的服务类型。
+ ///
public Type HandlerType { get; } = handlerType;
+ ///
+ /// 获取执行流式请求处理器的调用委托。
+ ///
public StreamInvoker Invoker { get; } = invoker;
}
+ ///
+ /// 保存普通请求分发路径所需的 handler 服务类型、pipeline 服务类型与强类型调用委托。
+ /// 该绑定同时覆盖“直接请求处理”和“带 pipeline 的请求处理”两条路径。
+ ///
+ /// 请求响应类型。
private sealed class RequestDispatchBinding(
Type handlerType,
Type behaviorType,
RequestInvoker requestInvoker,
RequestPipelineInvoker pipelineInvoker)
{
+ ///
+ /// 获取请求处理器在容器中的服务类型。
+ ///
public Type HandlerType { get; } = handlerType;
+ ///
+ /// 获取 pipeline 行为在容器中的服务类型。
+ ///
public Type BehaviorType { get; } = behaviorType;
+ ///
+ /// 获取直接调用请求处理器的强类型委托。
+ ///
public RequestInvoker RequestInvoker { get; } = requestInvoker;
+ ///
+ /// 获取执行 pipeline 行为链的强类型委托。
+ ///
public RequestPipelineInvoker PipelineInvoker { get; } = pipelineInvoker;
}
}
diff --git a/GFramework.Cqrs/Internal/WeakKeyCache.cs b/GFramework.Cqrs/Internal/WeakKeyCache.cs
index fffe006b..7377c2ca 100644
--- a/GFramework.Cqrs/Internal/WeakKeyCache.cs
+++ b/GFramework.Cqrs/Internal/WeakKeyCache.cs
@@ -50,6 +50,39 @@ internal sealed class WeakKeyCache
}
}
+ ///
+ /// 获取指定键对应的缓存值;若当前未命中,则在锁保护下使用附加状态创建并写入。
+ ///
+ /// 创建缓存值时需要携带的附加状态类型。
+ /// 缓存键。
+ /// 创建缓存值时复用的附加状态。
+ /// 基于键与附加状态创建缓存值的工厂方法。
+ /// 已存在或新创建的缓存值。
+ ///
+ /// 或 为 。
+ ///
+ public TValue GetOrAdd(TKey key, TState state, Func valueFactory)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+ ArgumentNullException.ThrowIfNull(valueFactory);
+
+ var entries = Volatile.Read(ref _entries);
+ if (entries.TryGetValue(key, out var cachedValue))
+ return cachedValue;
+
+ lock (_gate)
+ {
+ entries = _entries;
+ if (entries.TryGetValue(key, out cachedValue))
+ return cachedValue;
+
+ var createdValue = valueFactory(key, state);
+ ArgumentNullException.ThrowIfNull(createdValue);
+ entries.Add(key, createdValue);
+ return createdValue;
+ }
+ }
+
///
/// 尝试读取当前缓存中的值,而不触发新的创建逻辑。
///
@@ -125,7 +158,8 @@ internal sealed class WeakTypePairCache
var secondaryEntries = _entries.GetOrAdd(primaryType, static _ => new WeakKeyCache());
return secondaryEntries.GetOrAdd(
secondaryType,
- _ => valueFactory(primaryType, secondaryType));
+ (PrimaryType: primaryType, Factory: valueFactory),
+ static (cachedSecondaryType, state) => state.Factory(state.PrimaryType, cachedSecondaryType));
}
///
diff --git a/docs/zh-CN/core/cqrs.md b/docs/zh-CN/core/cqrs.md
index 257e29c4..0c248a96 100644
--- a/docs/zh-CN/core/cqrs.md
+++ b/docs/zh-CN/core/cqrs.md
@@ -83,6 +83,7 @@ public class GetPlayerQuery : QueryBase
处理器负责执行命令或查询的具体逻辑:
```csharp
+using GFramework.Cqrs.Command;
using GFramework.Cqrs.Cqrs.Command;
// 命令处理器