refactor(cqrs): 删除 pointer 运行时重建残留

- 重构 CqrsHandlerRegistryGenerator 的运行时类型引用模型,移除不可达的 pointer 子结构

- 删除 SourceEmission 中已失效的 MakePointerType 发射分支,保持 pointer 拒绝语义不变

- 更新 cqrs-rewrite 跟踪与 trace,记录本轮清理和定向验证结果
This commit is contained in:
gewuyou 2026-04-29 17:40:44 +08:00 committed by GeWuYou
parent e51b64f8d5
commit 5365f9aec2
5 changed files with 65 additions and 50 deletions

View File

@ -60,7 +60,6 @@ public sealed partial class CqrsHandlerRegistryGenerator
string? ReflectionAssemblyName,
RuntimeTypeReferenceSpec? ArrayElementTypeReference,
int ArrayRank,
RuntimeTypeReferenceSpec? PointerElementTypeReference,
RuntimeTypeReferenceSpec? GenericTypeDefinitionReference,
ImmutableArray<RuntimeTypeReferenceSpec> GenericTypeArguments)
{
@ -76,7 +75,6 @@ public sealed partial class CqrsHandlerRegistryGenerator
null,
0,
null,
null,
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
}
@ -92,7 +90,6 @@ public sealed partial class CqrsHandlerRegistryGenerator
null,
0,
null,
null,
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
}
@ -110,7 +107,6 @@ public sealed partial class CqrsHandlerRegistryGenerator
null,
0,
null,
null,
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
}
@ -126,7 +122,6 @@ public sealed partial class CqrsHandlerRegistryGenerator
elementTypeReference,
arrayRank,
null,
null,
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
}
@ -143,7 +138,6 @@ public sealed partial class CqrsHandlerRegistryGenerator
null,
null,
0,
null,
genericTypeDefinitionReference,
genericTypeArguments);
}

View File

@ -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))
{

View File

@ -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})";
}
/// <summary>
/// 发射指针类型引用的运行时重建表达式。
/// </summary>
/// <param name="builder">生成源码构造器。</param>
/// <param name="runtimeTypeReference">指针类型引用描述。</param>
/// <param name="variableBaseName">用于递归生成变量名的稳定前缀。</param>
/// <param name="reflectedArgumentNames">需要空值检查的反射解析变量集合。</param>
/// <param name="indent">当前生成语句的缩进。</param>
/// <returns>指针类型表达式。</returns>
private static string AppendPointerRuntimeTypeReferenceResolution(
StringBuilder builder,
RuntimeTypeReferenceSpec runtimeTypeReference,
string variableBaseName,
ICollection<string> reflectedArgumentNames,
string indent)
{
var pointedAtExpression = AppendRuntimeTypeReferenceResolution(
builder,
runtimeTypeReference.PointerElementTypeReference!,
$"{variableBaseName}PointedAt",
reflectedArgumentNames,
indent);
return $"{pointedAtExpression}.MakePointerType()";
}
/// <summary>
/// 发射已构造泛型类型引用的运行时重建表达式。
/// </summary>

View File

@ -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` 作为独立验证步骤

View File

@ -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` 复核远端信号