Skip to content

Refactor/Decouple handler registry generator from interface discovery reflection#230

Merged
GeWuYou merged 3 commits into
refactor/cqrs-architecture-decouplingfrom
refactor/cqrs-architecture-decoupling-todo-9
Apr 16, 2026
Merged

Refactor/Decouple handler registry generator from interface discovery reflection#230
GeWuYou merged 3 commits into
refactor/cqrs-architecture-decouplingfrom
refactor/cqrs-architecture-decoupling-todo-9

Conversation

@GeWuYou
Copy link
Copy Markdown
Owner

@GeWuYou GeWuYou commented Apr 16, 2026

Summary by CodeRabbit

  • 优化

    • 改进 CQRS 处理程序注册生成逻辑,生成结果更确定且更稳健,增强对隐藏类型、数组响应和复杂泛型封装的支持,提升注册准确性与运行时兼容性。
  • 测试

    • 扩展测试覆盖,新增隐藏类型与复杂泛型场景的用例,确保生成器在更多边界条件下的正确性和稳定性。

GeWuYou added 2 commits April 16, 2026 12:50
- 实现 CqrsHandlerRegistryGenerator 源代码生成器
- 为 CQRS 请求处理器、通知处理器和流请求处理器生成注册代码
- 减少运行时程序集反射扫描开销
- 支持直接类型引用和反射加载两种注册方式
- 提供完整的单元测试验证生成器功能
- 实现对私有嵌套类型的反射注册支持
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 16, 2026

📝 Walkthrough

Walkthrough

源生成器重构了 CQRS 处理程序注册逻辑:从接口扫描的共享反射助手改为按接口分支的确定性注册路径,新增精确反射重建(支持数组与构造泛型)并在必要时发出运行时类型解析代码。

Changes

Cohort / File(s) Summary
处理程序注册生成器核心逻辑
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
重构候选转换以生成三类注册 spec(直接 typeof、反射实现、精确反射);扩展 HandlerCandidateAnalysis 以携带额外数组和反射元数据;新增并条件发出多条代码路径:AppendReflectedImplementationRegistrationsAppendPreciseReflectedRegistrationsAppendPreciseReflectedTypeResolutionAppendRuntimeTypeReferenceResolution,并仅在需要时输出反射帮助方法。
生成器测试与期望输出
GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
更新和新增测试用例与字符串常量:移除共享的 RegisterReflectedHandler 期待;改为在测试期望中直接使用 registryAssembly.GetType(...)MakeGenericType/MakeArrayType 构建闭合服务类型,覆盖隐藏类型、数组响应与递归泛型重建场景。

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确地反映了核心变更——将处理器注册生成器从接口发现反射中重构解耦,与两个文件的实质性改动相符。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/cqrs-architecture-decoupling-todo-9

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs (1)

231-256: 缺少 XML 文档注释

新增的 TryCreatePreciseReflectedRegistrationTryCreateRuntimeTypeReferenceTryCreateGenericTypeDefinitionReference 等方法缺少 XML 文档注释。根据编码规范,所有非公开的关键方法也应包含文档说明,特别是生成器管道中的核心逻辑。

建议为这些方法添加 <summary><param> 文档,说明:

  • 方法的用途和语义假设
  • 返回 false 时的回退行为
  • 递归处理的边界条件

As per coding guidelines: "Generated logic and source generator pipelines MUST explain what is generated, why it is generated, semantic assumptions, and diagnostic or fallback behavior."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs` around
lines 231 - 256, 为新增的非公开方法添加完整的 XML 文档注释:在
TryCreatePreciseReflectedRegistration、TryCreateRuntimeTypeReference 和
TryCreateGenericTypeDefinitionReference 上添加 <summary> 描述方法用途和语义假设、每个 <param>
解释参数含义(例如 compilation、handlerInterface、typeArgument 等)、<returns> 说明何时返回
true/false 以及返回 false 时的回退行为/调用方预期,以及 <remarks> 或 <exception>
说明递归处理的边界条件和任何诊断/故障情形(例如无法解析类型时的行为);确保注释中提及生成器输出的语义(为何生成
PreciseReflectedRegistrationSpec、与 GetLogDisplayName 的关系)以满足生成器管道的文档规范。
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs`:
- Around line 231-256: 为新增的非公开方法添加完整的 XML 文档注释:在
TryCreatePreciseReflectedRegistration、TryCreateRuntimeTypeReference 和
TryCreateGenericTypeDefinitionReference 上添加 <summary> 描述方法用途和语义假设、每个 <param>
解释参数含义(例如 compilation、handlerInterface、typeArgument 等)、<returns> 说明何时返回
true/false 以及返回 false 时的回退行为/调用方预期,以及 <remarks> 或 <exception>
说明递归处理的边界条件和任何诊断/故障情形(例如无法解析类型时的行为);确保注释中提及生成器输出的语义(为何生成
PreciseReflectedRegistrationSpec、与 GetLogDisplayName 的关系)以满足生成器管道的文档规范。

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a71da273-46f0-446e-83ad-2ffcde907579

📥 Commits

Reviewing files that changed from the base of the PR and between ba6a358 and f25353d.

📒 Files selected for processing (2)
  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Code Quality & Security
  • GitHub Check: Analyze (C#)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: LoggerGenerator must automatically generate log fields and logging helper methods for classes decorated with [Log] attribute
PriorityGenerator must generate priority comparison implementations for classes decorated with [Priority] attribute
EnumExtensionsGenerator must generate enum extension capabilities for enums decorated with [GenerateEnumExtensions] attribute
ContextAwareGenerator must automatically implement IContextAware boilerplate logic for classes decorated with [ContextAware] attribute

**/*.cs: All public, protected, and internal types and members MUST include XML documentation comments (///) with <summary>, <param>, <returns>, <exception>, and <remarks> where applicable
Add inline comments for non-trivial logic, concurrency/threading behavior, performance-sensitive paths, workarounds, compatibility constraints, and edge cases
Core framework components (Architecture, Module, System, Context, Registry, Service Module, Lifecycle types) MUST include high-level explanations of responsibilities, lifecycle, interactions, and design rationale
Generated logic and source generator pipelines MUST explain what is generated, why it is generated, semantic assumptions, and diagnostic or fallback behavior
Methods with non-trivial logic MUST document the core idea, key decisions, and edge case handling
Do not rely on implicit imports; declare every required using explicitly in C# files
Write null-safe code that respects nullable annotations instead of suppressing warnings by default
Use the namespace pattern GFramework.{Module}.{Feature} with PascalCase segments
Follow standard C# naming: Types, methods, properties, events, constants use PascalCase; interfaces use I prefix; parameters and locals use camelCase; private fields use _camelCase
Use 4 spaces for indentation (not tabs), use Allman braces, and keep using directives at the top of the file sorted consistently
Prefer one primary type per file unless the surrounding project alread...

Files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
**/*.{cs,csproj}

📄 CodeRabbit inference engine (AGENTS.md)

Every non-trivial feature, bug fix, or behavior change MUST include tests or an explicit justification for why a test is not practical

Files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
**/*SourceGenerators/**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

Keep source generators deterministic and free of hidden environment or network dependencies

Files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-05T15:30:46.211Z
Learning: Implement CQRS pattern (Command Query Responsibility Segregation) with support for both synchronous and asynchronous execution, using Mediator pattern integrated via source code generators
📚 Learning: 2026-04-14T01:59:40.041Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-14T01:59:40.041Z
Learning: Applies to **/*.cs : Preserve deterministic behavior in registries, lifecycle orchestration, and generated outputs

Applied to files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
📚 Learning: 2026-04-14T01:59:40.041Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-14T01:59:40.041Z
Learning: Applies to **/*.Tests/*.cs : Source generator changes MUST be covered by generator tests; preserve snapshot-based verification patterns already used in the repository

Applied to files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
📚 Learning: 2026-04-14T01:59:40.041Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-14T01:59:40.041Z
Learning: Applies to **/*SourceGenerators/**/*.cs : Keep source generators deterministic and free of hidden environment or network dependencies

Applied to files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
📚 Learning: 2026-04-14T01:59:40.041Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-14T01:59:40.041Z
Learning: Applies to **/*.Tests/*.cs : When generator behavior changes intentionally, update snapshots together with the implementation

Applied to files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
📚 Learning: 2026-04-14T01:59:40.041Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-14T01:59:40.041Z
Learning: Applies to **/*.cs : Generated logic and source generator pipelines MUST explain what is generated, why it is generated, semantic assumptions, and diagnostic or fallback behavior

Applied to files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
📚 Learning: 2026-04-14T01:59:40.041Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-14T01:59:40.041Z
Learning: Applies to **/*.cs : Avoid hidden side effects in property getters, constructors, and registration helpers

Applied to files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
📚 Learning: 2026-04-06T12:45:43.921Z
Learnt from: GeWuYou
Repo: GeWuYou/GFramework PR: 190
File: GFramework.Game/Config/GameConfigBootstrap.cs:1-3
Timestamp: 2026-04-06T12:45:43.921Z
Learning: In the GeWuYou/GFramework repository, C# files may omit explicit `using System*` imports because the project-wide `GlobalUsings.cs` (referenced via manual global `using` directives) supplies common namespaces (e.g., `System`, `System.Threading`, `System.Threading.Tasks`). During code review, do not flag missing `using System...` directives in `.cs` files as long as `GlobalUsings.cs` is present/used to provide those namespaces.

Applied to files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
📚 Learning: 2026-04-14T01:59:40.041Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-14T01:59:40.041Z
Learning: Applies to **/*.cs : Public API changes must be covered by unit or integration tests

Applied to files:

  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
📚 Learning: 2026-04-14T01:59:40.041Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-14T01:59:40.041Z
Learning: Applies to **/*.Tests/*.cs : Keep tests focused on observable behavior, not implementation trivia

Applied to files:

  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
📚 Learning: 2026-04-14T01:59:40.041Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-14T01:59:40.041Z
Learning: Applies to **/*.Tests/*.cs : When a public API defines multiple contract branches, tests MUST cover meaningful variants including null, empty, default, and filtered inputs when those branches change behavior

Applied to files:

  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
🔇 Additional comments (9)
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs (5)

914-947: 设计良好的运行时类型引用规格

RuntimeTypeReferenceSpec 使用密封记录配合工厂方法的模式设计得很清晰,确保了不同类型引用场景(直接引用、反射查找、数组、构造泛型)的初始化一致性。这种设计也保证了不可变性,符合增量生成器的缓存需求。


640-723: 精确反射类型解析逻辑正确

AppendPreciseReflectedTypeResolution 方法虽然复杂度较高,但逻辑清晰:

  • 正确收集需要反射查找的类型变量名
  • 生成的 null 检查条件链确保运行时安全
  • 缩进层级管理正确

递归的 AppendRuntimeTypeReferenceResolution 正确处理了直接引用(返回 typeof(...) 表达式)、数组类型(.MakeArrayType())和构造泛型类型(.MakeGenericType(...))三种场景。


95-143: 分支逻辑覆盖完整

TransformHandlerCandidate 中的四条路径覆盖了所有可能的场景:

  1. 实现类型和处理器接口均可引用 → 直接注册
  2. 实现类型隐藏但接口可见 → 反射实现注册
  3. 接口参数可精确重建 → 精确反射注册
  4. 无法处理的边缘情况 → 回退到运行时接口发现

Lines 125-127 的注释清楚说明了回退场景的原因,符合生成器管道的文档要求。


992-1056: 相等性实现正确支持增量生成

HandlerCandidateAnalysisEqualsGetHashCode 实现正确包含了新增的 ReflectedImplementationRegistrationsPreciseReflectedRegistrations 数组比较,确保增量生成器的缓存机制能正确识别变更。

Based on learnings: "Preserve deterministic behavior in registries, lifecycle orchestration, and generated outputs."


442-449: 条件逻辑精确控制辅助方法生成

hasFullReflectionRegistrations 的判断条件正确识别了何时需要完整的反射发现辅助逻辑(即存在反射元数据名但没有反射实现注册或精确反射注册的情况)。这确保了 RegisterReflectedHandler 等辅助方法仅在必要时生成,优化了生成代码的体积。

GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs (4)

364-434: 新增测试覆盖隐藏实现的直接接口注册场景

此测试验证了当实现类型隐藏但处理器接口仍可被生成代码引用时,生成器只会通过反射查找实现类型,而不再生成基于 GetInterfaces() 的接口发现逻辑。这与 CqrsHandlerRegistryGenerator.cs 中 Lines 108-114 的 ReflectedImplementationRegistrationSpec 分支逻辑对应。

Based on learnings: "Source generator changes MUST be covered by generator tests."


436-507: 隐藏数组元素类型测试验证精确重建路径

此测试验证了精确重建路径能够递归处理隐藏元素类型的数组。期望输出中的 serviceType0_0Argument1Element.MakeArrayType() 调用与生成器中 AppendRuntimeTypeReferenceResolution 方法的数组处理逻辑一致。

测试场景设计合理:HiddenResponse[] 作为响应类型,元素类型 HiddenResponse 需要通过反射查找,然后调用 MakeArrayType() 构造数组类型。


509-580: 隐藏泛型定义测试验证递归泛型重建

此测试验证了精确重建路径能够处理隐藏泛型定义配合可见类型实参的场景。期望输出中的 serviceType0_0Argument1GenericDefinition.MakeGenericType(typeof(string)) 展示了正确的泛型类型构造流程:

  1. 通过反射查找 HiddenEnvelope\1` 泛型定义
  2. 使用 MakeGenericType(typeof(string)) 构造闭合类型
  3. 将结果作为 IRequestHandler<,> 的第二个类型参数

测试用例设计精准覆盖了生成器中 TryCreateGenericTypeDefinitionReferenceAppendRuntimeTypeReferenceResolution 的协作逻辑。


13-165: 期望输出字符串格式正确

多个期望输出常量使用了不同的缩进风格(如 HiddenNestedHandlerSelfRegistrationExpectedHiddenImplementationDirectInterfaceRegistrationExpected),这是原始字符串字面量保留精确格式的预期行为。测试框架会进行精确字符串比较,确保生成器输出的格式一致性。

@GeWuYou GeWuYou changed the title Refactor/cqrs architecture decoupling todo 9 Refactor/Decouple handler registry generator from interface discovery reflection Apr 16, 2026
- 实现了 CqrsHandlerRegistryGenerator 源代码生成器
- 减少运行时程序集反射扫描成本,提升性能
- 支持 IRequestHandler、INotificationHandler 和 IStreamRequestHandler 接口
- 自动为 CQRS 处理器生成服务注册代码
- 提供精确的运行时类型引用和反射注册功能
- 包含直接引用、数组和泛型类型的支持
- 生成带有日志记录的处理器注册代码
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs (3)

495-502: hasFullReflectionRegistrations 条件逻辑较为复杂,建议添加注释说明意图。

第 499-502 行的条件用于识别需要完整反射助手(RegisterReflectedHandler)的注册项。当前逻辑正确,但条件的含义不够直观——它筛选的是"有反射类型元数据名但没有精确反射路径"的情况。

💡 建议:添加注释或提取为命名方法
         var hasPreciseReflectedRegistrations = registrations.Any(static registration =>
             !registration.PreciseReflectedRegistrations.IsDefaultOrEmpty);
+        // Full reflection is needed when we have a metadata name but couldn't build
+        // precise reflected or reflected-implementation registrations for the handler.
         var hasFullReflectionRegistrations = registrations.Any(static registration =>
             !string.IsNullOrWhiteSpace(registration.ReflectionTypeMetadataName) &&
             registration.ReflectedImplementationRegistrations.IsDefaultOrEmpty &&
             registration.PreciseReflectedRegistrations.IsDefaultOrEmpty);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs` around
lines 495 - 502, The boolean expression that computes
hasFullReflectionRegistrations is non-obvious; update the code to clarify intent
by either adding a concise explanatory comment above this expression or
extracting the logic into a well-named helper method (e.g.,
IsFullReflectionRegistration) and use that method here; refer to the symbols
registrations, ReflectionTypeMetadataName, ReflectedImplementationRegistrations,
PreciseReflectedRegistrations and mention that this condition indicates entries
that have a ReflectionTypeMetadataName but lack both
ReflectedImplementationRegistrations and PreciseReflectedRegistrations (i.e.,
should use RegisterReflectedHandler).

1-27: 文件长度(约 1122 行)略超出 800-1000 行的建议上限。

当前文件包含了完整的源生成器逻辑,功能内聚性较高。如果后续需要添加更多注册策略或辅助方法,建议考虑将规格类型(*Spec 记录)和代码发射逻辑(Append* 方法)提取到单独的文件中。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs` around
lines 1 - 27, The CqrsHandlerRegistryGenerator class file is too large; refactor
by extracting the specification record types (any types named *Spec) and the
code-emission helper methods (methods named Append* ) into separate
partial-class files to keep CqrsHandlerRegistryGenerator focused; keep public
constants and generator entry points (CqrsHandlerRegistryGenerator, HintName,
GeneratedTypeName, GeneratedNamespace) in the main file and move supporting
types and Append* implementations into new files (e.g.,
CqrsHandlerRegistrySpecs.cs and CqrsHandlerRegistryEmitters.cs) so the generator
logic remains intact while reducing single-file length.

694-778: 类型解析代码生成处理了复杂场景。

该方法正确处理了混合场景:部分类型参数可通过 typeof() 解析,部分需要运行时反射。第 719-736 行的 null 检查仅针对反射解析的参数,避免了不必要的检查。

有一个小问题:第 735 行重新赋值 indent 变量可能导致代码可读性下降。

💡 建议:使用不同变量名避免重赋值
         if (reflectedArgumentNames.Count > 0)
         {
             builder.Append(indent);
             builder.Append("if (");
             // ... existing code ...
             builder.AppendLine("{");
-            indent = nestedIndent;
+            var currentIndent = nestedIndent;
+        }
+        else
+        {
+            var currentIndent = indent;
         }
+        // Then use currentIndent below...

或者保持现状,因为当前实现功能正确且局部变量重赋值在此上下文中是可接受的。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs` around
lines 694 - 778, AppendPreciseReflectedTypeResolution reassigns the local
variable indent to nestedIndent (line with "indent = nestedIndent;"), which
harms readability; instead introduce a new variable (e.g. bodyIndent or
currentIndent) and use that for subsequent builder.Append/AppendLine calls
inside the conditional block. Replace the single reassignment with "var
bodyIndent = nestedIndent;" and then update the subsequent uses (the lines that
write the registration, AddTransient call, logger.Debug, etc.) to use bodyIndent
where indent was used after the reassignment, leaving the original indent
variable unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs`:
- Around line 799-801: The code fails to distinguish SZ arrays because
RuntimeTypeReferenceSpec only records ArrayRank; update the
RuntimeTypeReferenceSpec to add a bool IsSZArray, set it in
RuntimeTypeReferenceSpec.FromArray (capture arrayType.IsSZArray), and then
change the MakeArrayType generation logic (the ternary that currently checks
runtimeTypeReference.ArrayRank == 1) to use IsSZArray: use .MakeArrayType() only
when Rank == 1 && IsSZArray == true, otherwise call .MakeArrayType(1) for Rank
== 1 non-SZ arrays and .MakeArrayType(n) for higher ranks.

---

Nitpick comments:
In `@GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs`:
- Around line 495-502: The boolean expression that computes
hasFullReflectionRegistrations is non-obvious; update the code to clarify intent
by either adding a concise explanatory comment above this expression or
extracting the logic into a well-named helper method (e.g.,
IsFullReflectionRegistration) and use that method here; refer to the symbols
registrations, ReflectionTypeMetadataName, ReflectedImplementationRegistrations,
PreciseReflectedRegistrations and mention that this condition indicates entries
that have a ReflectionTypeMetadataName but lack both
ReflectedImplementationRegistrations and PreciseReflectedRegistrations (i.e.,
should use RegisterReflectedHandler).
- Around line 1-27: The CqrsHandlerRegistryGenerator class file is too large;
refactor by extracting the specification record types (any types named *Spec)
and the code-emission helper methods (methods named Append* ) into separate
partial-class files to keep CqrsHandlerRegistryGenerator focused; keep public
constants and generator entry points (CqrsHandlerRegistryGenerator, HintName,
GeneratedTypeName, GeneratedNamespace) in the main file and move supporting
types and Append* implementations into new files (e.g.,
CqrsHandlerRegistrySpecs.cs and CqrsHandlerRegistryEmitters.cs) so the generator
logic remains intact while reducing single-file length.
- Around line 694-778: AppendPreciseReflectedTypeResolution reassigns the local
variable indent to nestedIndent (line with "indent = nestedIndent;"), which
harms readability; instead introduce a new variable (e.g. bodyIndent or
currentIndent) and use that for subsequent builder.Append/AppendLine calls
inside the conditional block. Replace the single reassignment with "var
bodyIndent = nestedIndent;" and then update the subsequent uses (the lines that
write the registration, AddTransient call, logger.Debug, etc.) to use bodyIndent
where indent was used after the reassignment, leaving the original indent
variable unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 432baff2-39f0-4379-a2b6-4de5985969ec

📥 Commits

Reviewing files that changed from the base of the PR and between f25353d and 082b240.

📒 Files selected for processing (1)
  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (C#)
  • GitHub Check: Code Quality & Security
🧰 Additional context used
📓 Path-based instructions (3)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: LoggerGenerator must automatically generate log fields and logging helper methods for classes decorated with [Log] attribute
PriorityGenerator must generate priority comparison implementations for classes decorated with [Priority] attribute
EnumExtensionsGenerator must generate enum extension capabilities for enums decorated with [GenerateEnumExtensions] attribute
ContextAwareGenerator must automatically implement IContextAware boilerplate logic for classes decorated with [ContextAware] attribute

**/*.cs: All public, protected, and internal types and members MUST include XML documentation comments (///) with <summary>, <param>, <returns>, <exception>, and <remarks> where applicable
Add inline comments for non-trivial logic, concurrency/threading behavior, performance-sensitive paths, workarounds, compatibility constraints, and edge cases
Core framework components (Architecture, Module, System, Context, Registry, Service Module, Lifecycle types) MUST include high-level explanations of responsibilities, lifecycle, interactions, and design rationale
Generated logic and source generator pipelines MUST explain what is generated, why it is generated, semantic assumptions, and diagnostic or fallback behavior
Methods with non-trivial logic MUST document the core idea, key decisions, and edge case handling
Do not rely on implicit imports; declare every required using explicitly in C# files
Write null-safe code that respects nullable annotations instead of suppressing warnings by default
Use the namespace pattern GFramework.{Module}.{Feature} with PascalCase segments
Follow standard C# naming: Types, methods, properties, events, constants use PascalCase; interfaces use I prefix; parameters and locals use camelCase; private fields use _camelCase
Use 4 spaces for indentation (not tabs), use Allman braces, and keep using directives at the top of the file sorted consistently
Prefer one primary type per file unless the surrounding project alread...

Files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
**/*.{cs,csproj}

📄 CodeRabbit inference engine (AGENTS.md)

Every non-trivial feature, bug fix, or behavior change MUST include tests or an explicit justification for why a test is not practical

Files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
**/*SourceGenerators/**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

Keep source generators deterministic and free of hidden environment or network dependencies

Files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-05T15:30:46.211Z
Learning: Implement CQRS pattern (Command Query Responsibility Segregation) with support for both synchronous and asynchronous execution, using Mediator pattern integrated via source code generators
📚 Learning: 2026-04-14T01:59:40.041Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-14T01:59:40.041Z
Learning: Applies to **/*.cs : Preserve deterministic behavior in registries, lifecycle orchestration, and generated outputs

Applied to files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
📚 Learning: 2026-04-14T01:59:40.041Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-14T01:59:40.041Z
Learning: Applies to **/*.cs : Avoid hidden side effects in property getters, constructors, and registration helpers

Applied to files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
📚 Learning: 2026-04-06T12:45:43.921Z
Learnt from: GeWuYou
Repo: GeWuYou/GFramework PR: 190
File: GFramework.Game/Config/GameConfigBootstrap.cs:1-3
Timestamp: 2026-04-06T12:45:43.921Z
Learning: In the GeWuYou/GFramework repository, C# files may omit explicit `using System*` imports because the project-wide `GlobalUsings.cs` (referenced via manual global `using` directives) supplies common namespaces (e.g., `System`, `System.Threading`, `System.Threading.Tasks`). During code review, do not flag missing `using System...` directives in `.cs` files as long as `GlobalUsings.cs` is present/used to provide those namespaces.

Applied to files:

  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
🔇 Additional comments (9)
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs (9)

89-143: 重构后的分支逻辑清晰,处理路径互斥且完整。

三层注册策略(直接引用 → 反射实现类型 → 精确反射接口 → 完整反射回退)设计合理,控制流通过 continue 和早期返回确保了路径互斥性。

有一个潜在的逻辑细节值得确认:当 canReferenceImplementation == truecanReferenceHandlerInterface == false 时,代码会尝试 TryCreatePreciseReflectedRegistration。如果成功,生成的 PreciseReflectedRegistrationSpec 会使用 typeof(implementationType) 而不是反射查找,这在 AppendPreciseReflectedRegistrations(第 651-657 行)中已正确处理。


248-274: 实现正确,XML 文档完整。

该方法正确使用 ConstructUnboundGenericType() 获取开放泛型类型的表示,递归处理类型参数的逻辑清晰。


293-347: 递归类型引用解析逻辑完善。

该方法正确处理了四种场景:直接引用、数组(含多维数组)、构造泛型和反射查找。第 337-343 行的逻辑确保只有当前程序集内的类型才会生成反射查找代码,外部不可访问类型会正确返回 false 触发更保守的回退路径。


366-390: 泛型定义解析实现正确。


608-643: 反射实现类型注册生成逻辑正确且安全。

使用 GetType(..., throwOnError: false, ...) 避免运行时异常,并在使用前进行 null 检查。生成的代码与运行时 CqrsHandlerRegistrar 的注册模式保持一致。


645-692: 精确反射注册生成逻辑完善。

根据实现类型的可引用性选择 typeof()GetType() 的分支处理正确。变量命名使用 registrationIndexregistrationOffset 的组合确保了生成代码中的唯一性。


972-1005: RuntimeTypeReferenceSpec 使用工厂方法模式清晰地表达了四种类型引用模式。

设计合理,工厂方法 (FromDirectReferenceFromReflectionLookupFromArrayFromConstructedGeneric) 提供了明确的构造语义。在 C# 缺少原生判别联合的情况下,这是一种可接受的实现方式。


968-1018: 新增的规格类型设计合理,使用 readonly record structImmutableArray 符合增量源生成器的最佳实践。


1050-1084: 相等性实现正确,对增量生成器缓存至关重要。

数组的逐元素比较确保了正确的相等性语义。考虑到 ImmutableArray<T>SequenceEqual 需要额外的 LINQ 调用和潜在的分配,当前的手动循环实现在源生成器场景下是合理的性能选择。

Comment on lines +799 to +801
return runtimeTypeReference.ArrayRank == 1
? $"{elementExpression}.MakeArrayType()"
: $"{elementExpression}.MakeArrayType({runtimeTypeReference.ArrayRank})";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

C# IArrayTypeSymbol Rank property SZ array vs multi-dimensional

💡 Result:

In C# Roslyn API, the IArrayTypeSymbol.Rank property returns the number of dimensions for any array type. It is 1 for single-dimensional arrays (whether SZArray or not), 2 for two-dimensional arrays, etc. SZArray (Single-dimensional, Zero-based array, like int[]) is distinguished using the IsSZArray property, which is true only for zero-based single-dimensional arrays (Rank == 1 && IsSZArray == true). Multi-dimensional arrays (like int[,]) and rectangular single-dimensional arrays with non-zero lower bounds have Rank == 1 but IsSZArray == false. Official Microsoft documentation confirms: - Rank: "Gets the number of dimensions of this array. A regular single-dimensional array has rank 1, a two-dimensional array has rank 2, etc." (Result 1, 4) - IsSZArray: "Is this a zero-based one-dimensional array, i.e. SZArray in CLR terms. SZArray is an array type encoded in metadata with ELEMENT_TYPE_SZARRAY (always single-dim array with 0 lower bound). Non-SZArray type is encoded in metadata with ELEMENT_TYPE_ARRAY and with optional sizes and lower bounds. Even though non-SZArray can also be a single-dim array" (Result 6) To differentiate: - Multi-dimensional: Rank > 1 - Single-dimensional SZArray: Rank == 1 && IsSZArray == true - Single-dimensional non-SZArray (rectangular with bounds): Rank == 1 && IsSZArray == false

Citations:


🏁 Script executed:

cat -n GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs | sed -n '780,838p'

Repository: GeWuYou/GFramework

Length of output: 3137


🏁 Script executed:

# Find RuntimeTypeReferenceSpec definition
fd -type f -name "*.cs" | xargs grep -l "class RuntimeTypeReferenceSpec\|record RuntimeTypeReferenceSpec\|struct RuntimeTypeReferenceSpec"

Repository: GeWuYou/GFramework

Length of output: 234


🏁 Script executed:

rg "class RuntimeTypeReferenceSpec|record RuntimeTypeReferenceSpec|struct RuntimeTypeReferenceSpec" --type cs

Repository: GeWuYou/GFramework

Length of output: 178


🏁 Script executed:

rg -A 15 "private sealed record RuntimeTypeReferenceSpec" GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs

Repository: GeWuYou/GFramework

Length of output: 793


🏁 Script executed:

rg -B 5 "ArrayElementTypeReference|ArrayRank" GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs | head -100

Repository: GeWuYou/GFramework

Length of output: 1056


🏁 Script executed:

rg "FromArrayType|new RuntimeTypeReferenceSpec.*Array|ArrayRank\s*=" GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs -A 3

Repository: GeWuYou/GFramework

Length of output: 273


🏁 Script executed:

rg "new RuntimeTypeReferenceSpec" GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs -B 2 -A 5

Repository: GeWuYou/GFramework

Length of output: 1365


🏁 Script executed:

rg "FromArray\(" GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs -B 2 -A 2

Repository: GeWuYou/GFramework

Length of output: 567


🏁 Script executed:

rg "IArrayTypeSymbol" GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs -B 3 -A 3

Repository: GeWuYou/GFramework

Length of output: 643


🏁 Script executed:

# Check if there's any IsSZArray usage or mention in the codebase
rg "IsSZArray" GFramework.SourceGenerators/

Repository: GeWuYou/GFramework

Length of output: 44


需要在 RuntimeTypeReferenceSpec 中追踪数组的 IsSZArray 属性。

当前代码仅根据 ArrayRank == 1 判断是否调用 MakeArrayType(),但存在逻辑缺陷:

根据 Roslyn 文档,IArrayTypeSymbol.Rank 对于单维数组始终返回 1,无论是 SZArray(T[])还是带边界的非 SZArray(T[*])。两种情况的区分应通过 IsSZArray 属性进行:

  • Rank == 1 && IsSZArray == true:使用 MakeArrayType()
  • Rank == 1 && IsSZArray == false:使用 MakeArrayType(1)

当前代码在 RuntimeTypeReferenceSpec.FromArray() 中仅记录 arrayType.Rank,没有捕获 IsSZArray 信息,导致无法正确区分这两种情况。需修改 RuntimeTypeReferenceSpec 添加 bool IsSZArray 字段,并在第 799-801 行的逻辑中予以检查。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs` around
lines 799 - 801, The code fails to distinguish SZ arrays because
RuntimeTypeReferenceSpec only records ArrayRank; update the
RuntimeTypeReferenceSpec to add a bool IsSZArray, set it in
RuntimeTypeReferenceSpec.FromArray (capture arrayType.IsSZArray), and then
change the MakeArrayType generation logic (the ternary that currently checks
runtimeTypeReference.ArrayRank == 1) to use IsSZArray: use .MakeArrayType() only
when Rank == 1 && IsSZArray == true, otherwise call .MakeArrayType(1) for Rank
== 1 non-SZ arrays and .MakeArrayType(n) for higher ranks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant