From 5365f9aec2ae25dc505aa8fce3f2b6b1a5cf9ddd Mon Sep 17 00:00:00 2001 From: gewuyou <95328647+GeWuYou@users.noreply.github.com> Date: Wed, 29 Apr 2026 17:40:44 +0800 Subject: [PATCH] =?UTF-8?q?refactor(cqrs):=20=E5=88=A0=E9=99=A4=20pointer?= =?UTF-8?q?=20=E8=BF=90=E8=A1=8C=E6=97=B6=E9=87=8D=E5=BB=BA=E6=AE=8B?= =?UTF-8?q?=E7=95=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重构 CqrsHandlerRegistryGenerator 的运行时类型引用模型,移除不可达的 pointer 子结构 - 删除 SourceEmission 中已失效的 MakePointerType 发射分支,保持 pointer 拒绝语义不变 - 更新 cqrs-rewrite 跟踪与 trace,记录本轮清理和定向验证结果 --- .../CqrsHandlerRegistryGenerator.Models.cs | 6 --- ...RegistryGenerator.RuntimeTypeReferences.cs | 6 --- ...HandlerRegistryGenerator.SourceEmission.cs | 34 --------------- .../todos/cqrs-rewrite-migration-tracking.md | 27 ++++++++++-- .../traces/cqrs-rewrite-migration-trace.md | 42 ++++++++++++++++++- 5 files changed, 65 insertions(+), 50 deletions(-) diff --git a/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.Models.cs b/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.Models.cs index e86ec1a0..ccd7e8cb 100644 --- a/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.Models.cs +++ b/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.Models.cs @@ -60,7 +60,6 @@ public sealed partial class CqrsHandlerRegistryGenerator string? ReflectionAssemblyName, RuntimeTypeReferenceSpec? ArrayElementTypeReference, int ArrayRank, - RuntimeTypeReferenceSpec? PointerElementTypeReference, RuntimeTypeReferenceSpec? GenericTypeDefinitionReference, ImmutableArray GenericTypeArguments) { @@ -76,7 +75,6 @@ public sealed partial class CqrsHandlerRegistryGenerator null, 0, null, - null, ImmutableArray.Empty); } @@ -92,7 +90,6 @@ public sealed partial class CqrsHandlerRegistryGenerator null, 0, null, - null, ImmutableArray.Empty); } @@ -110,7 +107,6 @@ public sealed partial class CqrsHandlerRegistryGenerator null, 0, null, - null, ImmutableArray.Empty); } @@ -126,7 +122,6 @@ public sealed partial class CqrsHandlerRegistryGenerator elementTypeReference, arrayRank, null, - null, ImmutableArray.Empty); } @@ -143,7 +138,6 @@ public sealed partial class CqrsHandlerRegistryGenerator null, null, 0, - null, genericTypeDefinitionReference, genericTypeArguments); } diff --git a/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.RuntimeTypeReferences.cs b/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.RuntimeTypeReferences.cs index bce72464..8157d45d 100644 --- a/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.RuntimeTypeReferences.cs +++ b/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.RuntimeTypeReferences.cs @@ -304,12 +304,6 @@ public sealed partial class CqrsHandlerRegistryGenerator return true; } - if (runtimeTypeReference.PointerElementTypeReference is not null && - ContainsExternalAssemblyTypeLookup(runtimeTypeReference.PointerElementTypeReference)) - { - return true; - } - if (runtimeTypeReference.GenericTypeDefinitionReference is not null && ContainsExternalAssemblyTypeLookup(runtimeTypeReference.GenericTypeDefinitionReference)) { diff --git a/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.SourceEmission.cs b/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.SourceEmission.cs index 4db622cb..9dd72b7f 100644 --- a/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.SourceEmission.cs +++ b/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.SourceEmission.cs @@ -662,14 +662,6 @@ public sealed partial class CqrsHandlerRegistryGenerator reflectedArgumentNames, indent); - if (runtimeTypeReference.PointerElementTypeReference is not null) - return AppendPointerRuntimeTypeReferenceResolution( - builder, - runtimeTypeReference, - variableBaseName, - reflectedArgumentNames, - indent); - if (runtimeTypeReference.GenericTypeDefinitionReference is not null) return AppendConstructedGenericRuntimeTypeReferenceResolution( builder, @@ -714,32 +706,6 @@ public sealed partial class CqrsHandlerRegistryGenerator : $"{elementExpression}.MakeArrayType({runtimeTypeReference.ArrayRank})"; } - /// - /// 发射指针类型引用的运行时重建表达式。 - /// - /// 生成源码构造器。 - /// 指针类型引用描述。 - /// 用于递归生成变量名的稳定前缀。 - /// 需要空值检查的反射解析变量集合。 - /// 当前生成语句的缩进。 - /// 指针类型表达式。 - private static string AppendPointerRuntimeTypeReferenceResolution( - StringBuilder builder, - RuntimeTypeReferenceSpec runtimeTypeReference, - string variableBaseName, - ICollection reflectedArgumentNames, - string indent) - { - var pointedAtExpression = AppendRuntimeTypeReferenceResolution( - builder, - runtimeTypeReference.PointerElementTypeReference!, - $"{variableBaseName}PointedAt", - reflectedArgumentNames, - indent); - - return $"{pointedAtExpression}.MakePointerType()"; - } - /// /// 发射已构造泛型类型引用的运行时重建表达式。 /// diff --git a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md index 6825adb2..af69ff10 100644 --- a/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md +++ b/ai-plan/public/cqrs-rewrite/todos/cqrs-rewrite-migration-tracking.md @@ -7,7 +7,7 @@ CQRS 迁移与收敛。 ## 当前恢复点 -- 恢复点编号:`CQRS-REWRITE-RP-054` +- 恢复点编号:`CQRS-REWRITE-RP-056` - 当前阶段:`Phase 8` - 当前焦点: - 当前功能历史已归档,active 跟踪仅保留 `Phase 8` 主线的恢复入口 @@ -23,6 +23,7 @@ CQRS 迁移与收敛。 - 已补充非法 CQRS 泛型合同的输入诊断断言,明确 `CS0306` 与 fallback / diagnostic 路径的组合语义 - 已为 registrar 的 reflection 注册路径补充 handler-interface 元数据缓存,减少跨容器重复注册时的 `GetInterfaces()` 反射 - 已将 registrar 的重复映射判定从线性扫描 `IServiceCollection` 收敛为本地映射索引,减少 fallback 注册路径的重复查找 + - 已完成一轮 `static lambda + state` 微收敛:`CqrsDispatcher` 与 `CqrsHandlerRegistrar` 现会在弱缓存 / 并发缓存入口优先使用无捕获工厂,继续压低热路径上的额外闭包分配 - 中期上继续 `Phase 8` 主线:参考 `ai-libs/Mediator`,继续扩大 generator 覆盖,并选择下一个收益明确的 dispatch / invoker 反射收敛点 ## 当前状态摘要 @@ -81,13 +82,21 @@ CQRS 迁移与收敛。 - `GFramework.SourceGenerators.Tests` 已新增“外部程序集隐藏泛型定义 + 可见类型实参”的 precise registration 回归 - 当前生成器会继续为这类 handler 合同发射 `ResolveReferencedAssemblyType(...) + MakeGenericType(...)` 组合,而不是退回字符串 fallback 元数据 - 本轮定向测试未暴露新的实现缺口,因此未改动 direct / named / mixed fallback 选择逻辑,也未调整 generator runtime type 建模实现 +- `2026-04-29` 已完成一轮缓存工厂闭包收敛: + - `CqrsDispatcher` 现会在 notification / stream / request binding 与 pipeline executor 缓存入口优先使用无捕获工厂 + - `CqrsHandlerRegistrar` 现会在程序集元数据缓存与可加载类型缓存入口复用 `static` 工厂 + 显式状态参数 + - 本轮未改动公开语义,也未修改 fallback 合同与 handler / behavior 生命周期边界 - `2026-04-29` 已完成一轮 request pipeline executor 形状缓存: - `CqrsDispatcher` 现会继续按 `requestType + responseType` 缓存 request dispatch binding,并在 binding 内按 `behaviorCount` 缓存强类型 pipeline executor - 每次分发只绑定当前 handler / behaviors 实例,不缓存容器解析结果,因此不改变 transient 生命周期与上下文注入语义 - `GFramework.Cqrs.Tests` 已补充 executor 首次创建 / 后续复用与双行为顺序回归 - `2026-04-29` 已完成一轮 CQRS 入口文档对齐: - `GFramework.Cqrs/README.md`、`docs/zh-CN/core/cqrs.md` 与 `docs/zh-CN/api-reference/index.md` 现已明确 generated registry 优先、targeted fallback 补齐剩余 handler 的当前语义 - - 当前工作区相对 `origin/main` 的累计 diff 已达到 `13 files / 709 lines`,仍低于本轮 `gframework-batch-boot 50` 的主要 stop condition +- `2026-04-29` 已完成一轮 generator pointer runtime-reconstruction 残留清理: + - `CqrsHandlerRegistryGenerator` 的运行时类型引用模型已移除不可达的 pointer 子结构 + - `SourceEmission` 不再保留 `MakePointerType()` 源码发射分支,`RuntimeTypeReferences` 也已删掉对应的外部程序集递归扫描死代码 + - pointer / function pointer 的拒绝语义保持不变,direct / named / mixed fallback 逻辑未改动 + - 当前工作区相对 `origin/main` 的累计 diff 已达到 `14 files`,仍低于本轮 `gframework-batch-boot 50` 的主要 stop condition - 当前主线优先级: - generator 覆盖面继续扩大 - dispatch/invoker 反射占比继续下降 @@ -162,9 +171,21 @@ CQRS 迁移与收敛。 - `dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release` - 结果:通过 - 备注:`0 warning / 0 error`;本轮确认 dispatcher request pipeline 形状缓存未破坏 `net8.0` / `net9.0` / `net10.0` 目标构建 +- `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~RegisterHandlers_Should_Cache_Assembly_Metadata_Across_Containers|FullyQualifiedName~RegisterHandlers_Should_Cache_Loadable_Types_Across_Containers|FullyQualifiedName~Dispatcher_Should_Cache_Request_Pipeline_Executors_Per_Behavior_Count"` + - 结果:通过 + - 备注:`3/3` 测试通过;本轮确认无捕获缓存工厂没有破坏 registrar / dispatcher 现有缓存行为 +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests"` + - 结果:通过 + - 备注:`22/22` 测试通过;本轮新增外部程序集隐藏泛型定义的 precise registration 回归 +- `dotnet build GFramework.Cqrs.SourceGenerators/GFramework.Cqrs.SourceGenerators.csproj -c Release` + - 结果:通过 + - 备注:`0 warning / 0 error`;本轮确认删除 pointer runtime-reconstruction 残留后生成器项目仍可正常构建 +- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests"` + - 结果:通过 + - 备注:`22/22` 测试通过;本轮确认 pointer / function pointer 拒绝语义保持不变,且未回归既有 precise runtime type lookup 场景 ## 下一步 -1. 继续 `Phase 8` 主线,优先再找一个收益明确且写集独立的 generator 或 dispatch 热点;当前累计 diff 为 `13 files / 709 lines`,距离 `50 files` stop condition 仍有余量 +1. 继续 `Phase 8` 主线,优先再找一个收益明确且写集独立的 generator 或 registrar/dispatcher 热点;在下一次提交后重新计算相对 `origin/main` 的累计 diff,并继续朝 `50 files` stop condition 推进 2. 若继续文档主线,优先再扫教程入口页与 API 参考中的 CQRS 采用说明,确认是否还有旧 Command / Query 迁移口径残留 3. 若后续再出现新的 PR review 或 review thread 变化,再重新执行 `$gframework-pr-review` 作为独立验证步骤 diff --git a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md index fc868571..a465b160 100644 --- a/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md +++ b/ai-plan/public/cqrs-rewrite/traces/cqrs-rewrite-migration-trace.md @@ -2,6 +2,46 @@ ## 2026-04-29 +### 阶段:pointer runtime-reconstruction 残留清理(CQRS-REWRITE-RP-056) + +- 延续 `gframework-batch-boot 50` 的 `Phase 8` 主线,本轮只处理一个写集很窄的 generator 清理切片:删除 `CqrsHandlerRegistryGenerator` 里已经不可达的 pointer runtime-reconstruction 残留 +- 先复核当前实现后确认: + - `TryCreateRuntimeTypeReference` 已在入口直接拒绝 `IPointerTypeSymbol` 与 `IFunctionPointerTypeSymbol` + - `CanReferenceFromGeneratedRegistry` 也已统一把 pointer / function pointer 判定为不可直接引用 + - 但 `RuntimeTypeReferenceSpec`、`AppendRuntimeTypeReferenceResolution(...)` 和 `ContainsExternalAssemblyTypeLookup(...)` 仍残留 pointer 子结构与 `MakePointerType()` 分支,属于已失效的死代码 +- 已完成的清理: + - `GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.Models.cs` 已移除 `PointerElementTypeReference` + - `GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.SourceEmission.cs` 已移除 pointer 运行时重建分支与 `AppendPointerRuntimeTypeReferenceResolution(...)` + - `GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.RuntimeTypeReferences.cs` 已移除 pointer 外部程序集查找递归 + - direct / named / mixed fallback 逻辑未改动,pointer / function pointer 拒绝语义保持不变 +- 定向验证已通过: + - `dotnet build GFramework.Cqrs.SourceGenerators/GFramework.Cqrs.SourceGenerators.csproj -c Release` + - `0 warning / 0 error` + - `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests"` + - `22/22` passed + +### 阶段:缓存工厂闭包收敛(CQRS-REWRITE-RP-055) + +- 延续 `gframework-batch-boot 50` 的 `Phase 8` 主线,本轮在不扩大语义面的前提下继续做一个更窄的 runtime 微切片:把弱缓存 / 并发缓存入口剩余的捕获型工厂收敛为 `static lambda + state` +- 先复核当前 runtime 热点后确认: + - `CqrsDispatcher` 的 notification / stream / request binding 与 pipeline executor 缓存仍存在少量可消除的捕获型工厂 + - `CqrsHandlerRegistrar` 的程序集元数据缓存与可加载类型缓存也仍通过捕获 `logger` 的 lambda 建值 + - 这些入口都只影响内部缓存建值,不触碰 handler / behavior 生命周期和 fallback 合同 +- 已完成的收敛: + - `CqrsDispatcher` 现为 notification / stream / request binding 命中路径改用无捕获工厂;pipeline executor 缓存改为显式状态对象承载 `requestType` + - `CqrsHandlerRegistrar` 现为 `AssemblyMetadataCache` 与 `LoadableTypesCache` 改用 `static` 工厂 + `logger` 显式状态参数 + - 该批次没有改动 `RequestPipelineInvocation` 的 `next` 语义,也没有缓存 handler / behavior 实例 +- 同轮继续补了一个独立 generator 覆盖缺口: + - `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 新增“外部程序集隐藏泛型定义 + 可见类型实参”的 precise registration 回归 + - 该回归锁定生成器会输出 `ResolveReferencedAssemblyType("...ProtectedEnvelope\`1")` 与 `MakeGenericType(typeof(string))` 的组合,而不是退回程序集级字符串 fallback +- 定向验证已通过: + - `dotnet test GFramework.Cqrs.Tests/GFramework.Cqrs.Tests.csproj -c Release --filter "FullyQualifiedName~RegisterHandlers_Should_Cache_Assembly_Metadata_Across_Containers|FullyQualifiedName~RegisterHandlers_Should_Cache_Loadable_Types_Across_Containers|FullyQualifiedName~Dispatcher_Should_Cache_Request_Pipeline_Executors_Per_Behavior_Count"` + - `3/3` passed + - `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests"` + - `22/22` passed + - `dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release` + - `0 warning / 0 error` + ### 阶段:低风险并行批次收口(CQRS-REWRITE-RP-054) - 继续按 `gframework-batch-boot 50` 推进 `Phase 8`,本轮先完成批次评估后再并行拆分写集,避免把 generator、runtime 与 docs 改动揉进同一片上下文 @@ -197,6 +237,6 @@ ### 当前下一步 -1. 回到 `Phase 8` 主线,优先再找一个 generator 覆盖缺口,继续减少仍需程序集级字符串 fallback 元数据的 handler 场景 +1. 回到 `Phase 8` 主线,优先再找一个写集独立的 generator 或 runtime 热点;pointer runtime-reconstruction 残留已清空,后续不要恢复任何 `MakePointerType()` 发射路径 2. 若继续文档主线,优先补齐 `docs/zh-CN/api-reference` 与教程入口页中仍过时的 CQRS API / 命名空间表述 3. 若后续 review thread 或 PR 状态再次变化,再重新执行 `$gframework-pr-review` 复核远端信号