Skip to content

Refactor/cqrs architecture decoupling todo 7#226

Merged
GeWuYou merged 6 commits intorefactor/cqrs-architecture-decouplingfrom
refactor/cqrs-architecture-decoupling-todo-7
Apr 16, 2026
Merged

Refactor/cqrs architecture decoupling todo 7#226
GeWuYou merged 6 commits intorefactor/cqrs-architecture-decouplingfrom
refactor/cqrs-architecture-decoupling-todo-7

Conversation

@GeWuYou
Copy link
Copy Markdown
Owner

@GeWuYou GeWuYou commented Apr 16, 2026

Summary by CodeRabbit

发行说明

  • 新功能

    • 新增独立的 CQRS 公共契约(上下文 与 运行时 接口)与注册服务入口,支持异步、流式分发及注册点创建。
    • 引入程序集级回退标记,生成器可在需要时请求运行时反射回退。
  • 重构

    • 集中统一处理器注册与去重规则,改进别名/可见性去重并稳定注册顺序。
    • 注入/注册流程调整以提供兼容别名的运行时实例。
  • 测试

    • 扩展单元测试,覆盖注册、别名去重、回退与参数验证场景。

GeWuYou added 2 commits April 16, 2026 07:32
- 移除过时的Cqrs抽象引用
- 添加MicrosoftDiContainer实现IIocContainer接口
- 提供线程安全的依赖注入容器功能
- 支持单例、瞬态、作用域生命周期管理
- 实现CQRS请求管道行为注册功能
- 添加CqrsRuntimeModule服务模块
- 提供CQRS运行时实现和处理器注册器
- 扩展IArchitectureContext接口支持CQRS契约
- 实现 MicrosoftDiContainer 类,提供对 Microsoft.Extensions.DependencyInjection 的适配
- 添加线程安全的依赖注入容器功能,支持单例、瞬态和作用域服务注册
- 实现 CqrsRuntimeModule 模块,用于注册 CQRS 运行时组件
- 添加 CqrsRuntimeFactory 工厂类,提供 CQRS 运行时实现的创建入口
- 实现 DefaultCqrsRegistrationService,处理 CQRS 处理器的程序集注册
- 添加 CqrsTestRuntime 测试工具类,为测试环境提供 CQRS 运行时访问
- 支持多种注册方式包括实例注册、类型映射和工厂方法
- 实现服务获取、查询和生命周期管理功能
- 添加容器冻结机制以构建服务提供者
- 支持 CQRS 管道行为和处理器的批量注册功能
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

将 CQRS 运行时抽象迁移到独立包:新增 ICqrsContext/ICqrsRuntime,引入 ICqrsRegistrationService 与实现,调整调度器、IoC 注册与生成器回退标记并更新相关测试与容器去重逻辑。(不超过50字)

Changes

Cohort / File(s) Summary
CQRS 抽象层新增
GFramework.Cqrs.Abstractions/Cqrs/ICqrsContext.cs, GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
新增空标记接口 ICqrsContext 与运行时接口 ICqrsRuntime(包含 SendAsync/PublishAsync/CreateStream 签名)。
Core 抽象兼容层
GFramework.Core.Abstractions/Architectures/IArchitectureContext.cs, GFramework.Core.Abstractions/Cqrs/ICqrsRuntime.cs
IArchitectureContext 现在继承新 ICqrsContext;Core 层的 ICqrsRuntime 改为继承新抽象并作为兼容别名,添加 [EditorBrowsable(Never)],移除旧方法声明。
调度器与上下文适配
GFramework.Cqrs/Internal/CqrsDispatcher.cs
调度方法参数由 IArchitectureContextICqrsContext;PrepareHandler 在遇到 IContextAware 时要求传入上下文也实现 IArchitectureContext,否则抛出。
注册服务与去重实现
GFramework.Cqrs/ICqrsRegistrationService.cs, GFramework.Cqrs/Internal/DefaultCqrsRegistrationService.cs, GFramework.Cqrs/CqrsRuntimeFactory.cs
新增 ICqrsRegistrationService 与内部 DefaultCqrsRegistrationService(按程序集稳定键去重、跨次去重);在 CqrsRuntimeFactory 新增 CreateRegistrationService
IoC 与模块注册改动
GFramework.Core/Ioc/MicrosoftDiContainer.cs, GFramework.Core/Services/Modules/CqrsRuntimeModule.cs
将按程序集去重移到 ICqrsRegistrationService.RegisterHandlers(assemblies);容器未冻结时 GetAll 收集逻辑重构并引入“别名可见性”去重规则;模块显式预创建并注册 runtime/registrar 与 legacy 别名。
Core 调用点调整
GFramework.Core/Architectures/ArchitectureContext.cs
公开 CQRS 调度方法入参类型改为使用 Cqrs.Abstractions.Cqrs.* 对应接口。
生成器与反射回退
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs, GFramework.Cqrs/CqrsReflectionFallbackAttribute.cs
生成器引入 GenerationEnvironment 并在检测到不可见处理器且支持回退标记时,发出 assembly-level CqrsReflectionFallbackAttribute 以请求运行时反射回退。
注册器内部改进
GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs
将生成器返回值改为 GeneratedRegistrationResult 枚举以精确控制回退;在反射注册前新增 (handlerInterface, implType) 重复检测并跳过已注册映射。
测试与测试辅助更改
GFramework.Core.Tests/..., GFramework.Cqrs.Tests/..., GFramework.Tests.Common/CqrsTestRuntime.cs, GFramework.SourceGenerators.Tests/...
更新/新增多项测试覆盖:移除过时 using、增加 legacy alias 断言、检验容器别名去重逻辑、增加生成器回退场景与辅助测试类型。

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    rect rgba(135,206,250,0.5)
    participant RegistrationService as ICqrsRegistrationService
    end
    rect rgba(173,216,230,0.5)
    participant Registrar as ICqrsHandlerRegistrar
    end
    rect rgba(144,238,144,0.5)
    participant DI as IServiceCollection/Container
    end

    Caller->>RegistrationService: RegisterHandlers(assemblies)
    RegistrationService->>RegistrationService: 计算稳定键、去重(per-call & cross-call)
    RegistrationService->>Registrar: RegisterHandlers(assembly) for new assemblies
    Registrar->>DI: AddTransient(handlerInterface, implementationType) (跳过已存在 (service,impl) 映射)
    Registrar-->>RegistrationService: registration result
    RegistrationService->>RegistrationService: 记录已注册 assembly 键
    RegistrationService-->>Caller: 完成
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR标题准确反映了主要变更内容:将CQRS架构与核心框架解耦,通过引入ICqrsContext接口和重组ICqrsRuntime来实现架构分离。
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.

✏️ 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-7

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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
GFramework.Cqrs/Internal/DefaultCqrsRegistrationService.cs (1)

14-19: 考虑线程安全性

_registeredAssemblyKeys 使用普通 HashSet<string>,如果 RegisterHandlers 可能被多线程并发调用,则存在数据竞争风险。

根据当前使用场景(MicrosoftDiContainer.RegisterCqrsHandlersFromAssemblies 在写锁保护下调用),该服务实际上是在单线程语境下使用的。如果这是设计假设,建议在类级文档中明确说明线程安全约束;如果未来可能支持并发调用,则需改用 ConcurrentDictionary<string, byte> 或加锁保护。

📝 建议在文档中明确线程安全约束
 /// <summary>
 ///     默认的 CQRS 程序集注册协调器。
 /// </summary>
 /// <remarks>
 ///     该实现把"按稳定程序集键去重"和"委托给 handler registrar 执行实际映射注册"收敛到 CQRS runtime 内部,
 ///     避免外层容器继续了解 handler 注册流水线的内部结构。
+///     <para>
+///         该类型不是线程安全的。调用方应在外部同步(如容器写锁)下访问 <see cref="RegisterHandlers"/>。
+///     </para>
 /// </remarks>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.Cqrs/Internal/DefaultCqrsRegistrationService.cs` around lines 14 -
19, The field _registeredAssemblyKeys in DefaultCqrsRegistrationService is a
plain HashSet<string> which is unsafe if RegisterHandlers is ever called
concurrently; either document the class-level thread-safety contract (noting
that MicrosoftDiContainer.RegisterCqrsHandlersFromAssemblies currently calls it
under a write lock) or make it concurrency-safe by replacing the HashSet with a
thread-safe structure (e.g., ConcurrentDictionary<string, byte>) or protecting
accesses to _registeredAssemblyKeys with a lock around the RegisterHandlers
logic; update the class summary to state the chosen thread-safety assumption if
you keep the non-concurrent HashSet.
GFramework.Core/Ioc/MicrosoftDiContainer.cs (1)

602-609: 这里的按引用去重范围有点过宽。

现在未冻结路径会把“同一实例的重复出现”全部折叠掉,不区分它到底是“兼容别名接口造成的重复”,还是“同一 ServiceType 被显式注册了多次”。前者应该去重,但后者在 IServiceCollection 里是有语义的;当前实现会让未冻结态的 GetAll*/GetRequired* 比冻结后看到更少的结果。建议把去重条件收窄到“不同 ServiceType 指向同一实例”的别名场景。

Based on learnings: Applies to **/*.cs : Preserve deterministic behavior in registries, lifecycle orchestration, and generated outputs

Also applies to: 653-660

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

In `@GFramework.Core/Ioc/MicrosoftDiContainer.cs` around lines 602 - 609, The
current dedupe uses seenInstances.Add(instance) to collapse any repeated
ImplementationInstance regardless of why it was registered; change this so we
only dedupe when the same concrete instance is being exposed under different
ServiceType aliases. Implement a map from instance -> first-seen ServiceType
(e.g. Dictionary<object, Type> firstServiceTypeByInstance) while iterating
registeredServices: when descriptor.ImplementationInstance is T instance, if
instance not seen record
firstServiceTypeByInstance[instance]=descriptor.ServiceType and add to result;
if instance seen and firstServiceTypeByInstance[instance] !=
descriptor.ServiceType then skip (dedupe alias), but if
firstServiceTypeByInstance[instance] == descriptor.ServiceType then allow adding
the duplicate (preserve multiple registrations of same ServiceType). Update
logic at the block handling ImplementationInstance (and mirror same change at
the similar block around lines 653-660).
🤖 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.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs`:
- Around line 18-48: The three public methods SendAsync, PublishAsync, and
CreateStream on ICqrsRuntime lack XML docs for preconditions and thrown
exceptions; update their XML documentation to declare null-check requirements
and possible runtime failures: document that ICqrsContext and the
request/notification parameters must not be null (throwing
ArgumentNullException), that unsupported or incompatible ICqrsContext
combinations can cause ArgumentException, and that missing or failed handlers
may surface as InvalidOperationException or OperationCanceledException (when
cancellationToken is used); add <summary>, <param>, <returns>, and appropriate
<exception> tags (and <remarks> if needed) for SendAsync, PublishAsync and
CreateStream to reflect these constraints and the intended usage contract.

---

Nitpick comments:
In `@GFramework.Core/Ioc/MicrosoftDiContainer.cs`:
- Around line 602-609: The current dedupe uses seenInstances.Add(instance) to
collapse any repeated ImplementationInstance regardless of why it was
registered; change this so we only dedupe when the same concrete instance is
being exposed under different ServiceType aliases. Implement a map from instance
-> first-seen ServiceType (e.g. Dictionary<object, Type>
firstServiceTypeByInstance) while iterating registeredServices: when
descriptor.ImplementationInstance is T instance, if instance not seen record
firstServiceTypeByInstance[instance]=descriptor.ServiceType and add to result;
if instance seen and firstServiceTypeByInstance[instance] !=
descriptor.ServiceType then skip (dedupe alias), but if
firstServiceTypeByInstance[instance] == descriptor.ServiceType then allow adding
the duplicate (preserve multiple registrations of same ServiceType). Update
logic at the block handling ImplementationInstance (and mirror same change at
the similar block around lines 653-660).

In `@GFramework.Cqrs/Internal/DefaultCqrsRegistrationService.cs`:
- Around line 14-19: The field _registeredAssemblyKeys in
DefaultCqrsRegistrationService is a plain HashSet<string> which is unsafe if
RegisterHandlers is ever called concurrently; either document the class-level
thread-safety contract (noting that
MicrosoftDiContainer.RegisterCqrsHandlersFromAssemblies currently calls it under
a write lock) or make it concurrency-safe by replacing the HashSet with a
thread-safe structure (e.g., ConcurrentDictionary<string, byte>) or protecting
accesses to _registeredAssemblyKeys with a lock around the RegisterHandlers
logic; update the class summary to state the chosen thread-safety assumption if
you keep the non-concurrent HashSet.
🪄 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: d5951224-51b3-488d-b8d0-8ae7e1ca1095

📥 Commits

Reviewing files that changed from the base of the PR and between 385893c and a7604de.

📒 Files selected for processing (14)
  • GFramework.Core.Abstractions/Architectures/IArchitectureContext.cs
  • GFramework.Core.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.cs
  • GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs
  • GFramework.Core/Architectures/ArchitectureContext.cs
  • GFramework.Core/Ioc/MicrosoftDiContainer.cs
  • GFramework.Core/Services/Modules/CqrsRuntimeModule.cs
  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsContext.cs
  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Cqrs/CqrsRuntimeFactory.cs
  • GFramework.Cqrs/ICqrsRegistrationService.cs
  • GFramework.Cqrs/Internal/CqrsDispatcher.cs
  • GFramework.Cqrs/Internal/DefaultCqrsRegistrationService.cs
  • GFramework.Tests.Common/CqrsTestRuntime.cs
💤 Files with no reviewable changes (1)
  • GFramework.Core.Tests/Architectures/ArchitectureContextTests.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 (2)
**/*.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.Core.Abstractions/Architectures/IArchitectureContext.cs
  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsContext.cs
  • GFramework.Cqrs/ICqrsRegistrationService.cs
  • GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs
  • GFramework.Cqrs/CqrsRuntimeFactory.cs
  • GFramework.Cqrs/Internal/DefaultCqrsRegistrationService.cs
  • GFramework.Core/Services/Modules/CqrsRuntimeModule.cs
  • GFramework.Tests.Common/CqrsTestRuntime.cs
  • GFramework.Core/Ioc/MicrosoftDiContainer.cs
  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Core.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Cqrs/Internal/CqrsDispatcher.cs
  • GFramework.Core/Architectures/ArchitectureContext.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.Core.Abstractions/Architectures/IArchitectureContext.cs
  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsContext.cs
  • GFramework.Cqrs/ICqrsRegistrationService.cs
  • GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs
  • GFramework.Cqrs/CqrsRuntimeFactory.cs
  • GFramework.Cqrs/Internal/DefaultCqrsRegistrationService.cs
  • GFramework.Core/Services/Modules/CqrsRuntimeModule.cs
  • GFramework.Tests.Common/CqrsTestRuntime.cs
  • GFramework.Core/Ioc/MicrosoftDiContainer.cs
  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Core.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Cqrs/Internal/CqrsDispatcher.cs
  • GFramework.Core/Architectures/ArchitectureContext.cs
🧠 Learnings (10)
📚 Learning: 2026-04-05T15:30:46.211Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-05T15:30:46.211Z
Learning: IContextAware must provide unified context access through SetContext(IArchitectureContext) method for components to obtain architecture context

Applied to files:

  • GFramework.Core.Abstractions/Architectures/IArchitectureContext.cs
  • GFramework.Cqrs/Internal/CqrsDispatcher.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 : Reuse existing architecture test infrastructure when relevant: `ArchitectureTestsBase<T>`, `SyncTestArchitecture`, `AsyncTestArchitecture`

Applied to files:

  • GFramework.Core.Abstractions/Architectures/IArchitectureContext.cs
📚 Learning: 2026-04-05T15:30:46.211Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-05T15:30:46.211Z
Learning: Use IServiceModule pattern to register built-in services (EventBus, CommandExecutor, QueryExecutor) with Architecture

Applied to files:

  • GFramework.Core.Abstractions/Architectures/IArchitectureContext.cs
  • GFramework.Core/Services/Modules/CqrsRuntimeModule.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.Core.Abstractions/Architectures/IArchitectureContext.cs
  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsContext.cs
  • GFramework.Cqrs/ICqrsRegistrationService.cs
  • GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs
  • GFramework.Cqrs/CqrsRuntimeFactory.cs
  • GFramework.Cqrs/Internal/DefaultCqrsRegistrationService.cs
  • GFramework.Core/Services/Modules/CqrsRuntimeModule.cs
  • GFramework.Tests.Common/CqrsTestRuntime.cs
  • GFramework.Core/Ioc/MicrosoftDiContainer.cs
  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Core.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Cqrs/Internal/CqrsDispatcher.cs
  • GFramework.Core/Architectures/ArchitectureContext.cs
📚 Learning: 2026-04-05T15:30:46.211Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-05T15:30:46.211Z
Learning: Use MicrosoftDiContainer wrapping Microsoft.Extensions.DependencyInjection for unified component registration and service resolution

Applied to files:

  • GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs
  • GFramework.Core/Services/Modules/CqrsRuntimeModule.cs
  • GFramework.Tests.Common/CqrsTestRuntime.cs
  • GFramework.Core/Ioc/MicrosoftDiContainer.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.Core.Tests/Ioc/MicrosoftDiContainerTests.cs
📚 Learning: 2026-04-05T15:30:46.211Z
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

Applied to files:

  • GFramework.Cqrs/CqrsRuntimeFactory.cs
  • GFramework.Core/Architectures/ArchitectureContext.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 : Use the namespace pattern `GFramework.{Module}.{Feature}` with PascalCase segments

Applied to files:

  • GFramework.Core/Services/Modules/CqrsRuntimeModule.cs
  • GFramework.Core/Ioc/MicrosoftDiContainer.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.Core/Ioc/MicrosoftDiContainer.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 : Preserve deterministic behavior in registries, lifecycle orchestration, and generated outputs

Applied to files:

  • GFramework.Core/Ioc/MicrosoftDiContainer.cs
🔇 Additional comments (12)
GFramework.Cqrs/ICqrsRegistrationService.cs (1)

1-19: LGTM!

接口设计简洁,职责单一,XML 文档完整地描述了接口的用途与语义(程序集去重 + 生成注册器优先 + 反射回退)。命名符合 ICqrsRegistrationService 规范,与 CqrsRuntimeFactory.CreateRegistrationService 工厂方法及 DefaultCqrsRegistrationService 实现形成清晰的契约链路。

GFramework.Cqrs.Abstractions/Cqrs/ICqrsContext.cs (1)

1-13: LGTM!

作为轻量级 marker seam 的设计意图在文档中表述清晰。该接口成功将 ICqrsRuntimeGFramework.Core.AbstractionsIArchitectureContext 解耦,同时保留了对 IContextAware 处理器的兼容注入能力。

GFramework.Core.Abstractions/Architectures/IArchitectureContext.cs (1)

8-8: LGTM!

IArchitectureContext 继承 ICqrsContext 的设计符合 Liskov 替换原则——由于 ICqrsContext 是空的 marker interface,现有的所有 IArchitectureContext 实现自动满足新契约,保证了向后兼容性。

这一变更使得 CqrsDispatcher 的分发方法可以接受更宽泛的 ICqrsContext 参数,同时现有使用 IArchitectureContext 的代码无需修改即可继续工作。

Also applies to: 21-21

GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs (1)

9-9: LGTM!

测试用例正确验证了 legacy runtime 兼容性别名的关键行为:

  1. ICqrsRuntimeLegacyICqrsRuntime 各返回恰好一个实例
  2. 两者解析到同一个对象实例(Is.SameAs
  3. RegisterHandlers 调用前后断言保持一致,验证了幂等注册语义

这与 MicrosoftDiContainer.GetAll<T>() 中使用 ReferenceEqualityComparer 进行实例去重的实现相呼应。

Also applies to: 162-173

GFramework.Tests.Common/CqrsTestRuntime.cs (1)

10-10: LGTM!

测试基础设施的更新与生产代码 CqrsRuntimeModule 的注册模式保持一致:

  1. 同时注册 ICqrsRuntimeLegacyICqrsRuntime(指向同一实例)
  2. 新增 ICqrsRegistrationService 的幂等注册
  3. Lines 66-69 的 fallback 逻辑处理了 runtime 已存在但 legacy 别名缺失的边缘情况

类型转换 (LegacyICqrsRuntime)runtime 是安全的,因为 CqrsDispatcher 实现的 ICqrsRuntime 继承自 legacy 接口。

Also applies to: 63-84

GFramework.Cqrs/CqrsRuntimeFactory.cs (1)

50-66: LGTM!

工厂方法 CreateRegistrationService 与现有的 CreateRuntimeCreateHandlerRegistrar 保持一致的设计风格:

  • 参数校验使用 ArgumentNullException.ThrowIfNull
  • 返回抽象接口而非暴露内部实现类型
  • XML 文档完整覆盖所有参数和异常

这符合类级注释中描述的设计目标——"在不暴露内部实现细节的前提下接入默认 CQRS runtime"。

GFramework.Core/Services/Modules/CqrsRuntimeModule.cs (1)

6-6: LGTM!

模块注册逻辑清晰且依赖顺序正确:

  1. 先创建 runtimeregistrar 实例
  2. runtime 同时注册为 ICqrsRuntimeLegacyICqrsRuntime(同一实例)
  3. 注册 registrar 后再创建依赖它的 ICqrsRegistrationService

这确保了:

  • Legacy 代码继续通过旧命名空间接口访问 runtime
  • 新代码使用 GFramework.Cqrs.Abstractions.Cqrs.ICqrsRuntime
  • 两者解析到同一对象,行为一致

Also applies to: 42-50

GFramework.Cqrs/Internal/DefaultCqrsRegistrationService.cs (1)

25-48: LGTM!

RegisterHandlers 方法设计合理:

  • 双层去重策略(processedAssemblyKeys 处理单次调用内重复,_registeredAssemblyKeys 处理跨调用重复)
  • 使用 OrderBy(GetAssemblyRegistrationKey) 确保注册顺序的确定性
  • 跳过已注册程序集时输出 Debug 日志,便于诊断

GetAssemblyRegistrationKey 的 fallback 链 (FullName ?? GetName().Name ?? ToString()) 能稳健处理各种程序集场景。

GFramework.Core.Abstractions/Cqrs/ICqrsRuntime.cs (1)

5-15: 这个兼容别名收口方式是稳的。

旧接口改成继承新契约的 shim,并且把迁移方向写进文档,能同时保住既有公开路径和新的抽象分层。

GFramework.Core/Architectures/ArchitectureContext.cs (1)

192-223: 这几处 API 签名切换和新的 runtime seam 是一致的。

查询/命令入口统一对齐到 GFramework.Cqrs.Abstractions 契约,而且方法体没有引入额外分叉,迁移成本比较低。

Also applies to: 354-397

GFramework.Cqrs/Internal/CqrsDispatcher.cs (1)

157-165: ⚠️ Potential issue | 🟠 Major

新的 ICqrsContext seam 这里还没有真正脱离 IArchitectureContext

只要命中的 handler/behavior 实现了 IContextAware,这里就会强制把 ICqrsContext 向下转成 IArchitectureContext。这样一来,任何只实现新抽象的上下文都会在运行时抛 InvalidOperationException,实际可用契约仍然是“ICqrsContext,但很多情况下还必须同时是 IArchitectureContext”。如果这个 PR 的目标是把 runtime 从 Core 架构上下文解耦,这里还需要一起抽离 IContextAware 的注入契约,或者提供一个明确的适配层。

Based on learnings: IContextAware must provide unified context access through SetContext(IArchitectureContext) method for components to obtain architecture context

⛔ Skipped due to learnings
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-05T15:30:46.211Z
Learning: IContextAware must provide unified context access through SetContext(IArchitectureContext) method for components to obtain architecture context
GFramework.Core/Ioc/MicrosoftDiContainer.cs (1)

399-403: 不需要调整锁的持有范围,当前设计是安全的。

ResolveCqrsRegistrationService() 只读取 GetServicesUnsafe,而 CqrsHandlerRegistrar.RegisterHandlers() 通过 IServiceCollection.AddTransient() 注册处理器,不会回调容器的 Register* 方法。因此不存在写锁重入风险。该锁设计正确地保护了初始化期间的注册操作。

			> Likely an incorrect or invalid review comment.

Comment thread GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
GeWuYou added 2 commits April 16, 2026 08:49
- 实现 CqrsHandlerRegistrar 类用于扫描并注册 CQRS 处理器
- 添加源码生成器自动生成 CQRS 处理器注册器减少反射开销
- 实现运行时回退机制在生成注册器不可用时使用反射扫描
- 添加完整的单元测试验证处理器注册顺序和容错行为
- 支持请求、通知和流式处理器的自动注册功能
- 实现稳定的处理器注册顺序保证跨环境一致性
- 添加详细的诊断日志记录注册过程和异常情况
- 在GlobalUsings.cs文件中新增System.Reflection的全局引用
- 便于后续代码中直接使用Reflection相关功能
- 减少重复的using声明语句
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.Cqrs/Internal/CqrsHandlerRegistrar.cs (1)

234-242: 考虑大型程序集场景下的性能影响。

IsHandlerMappingAlreadyRegistered 对每个处理器接口执行 O(n) 的线性扫描。在典型场景下(数十到数百个处理器)这是可接受的,但对于大型代码库,可能存在 O(n²) 的整体复杂度。

如果未来出现性能问题,可考虑使用 HashSet<(Type, Type)> 进行去重检查。当前实现对大多数场景足够,但建议添加注释说明性能特征。

💡 可选优化:使用 HashSet 进行快速去重
+    // 若服务集合较大,可在调用方维护一个 HashSet 进行 O(1) 去重检查。
     private static bool IsHandlerMappingAlreadyRegistered(
         IServiceCollection services,
         Type handlerInterface,
         Type implementationType)
     {
         return services.Any(descriptor =>
             descriptor.ServiceType == handlerInterface &&
             descriptor.ImplementationType == implementationType);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs` around lines 234 - 242, The
IsHandlerMappingAlreadyRegistered method currently does a linear Any scan over
IServiceCollection for each handler mapping which is O(n) per check and can lead
to O(n²) behavior at scale; update the code by adding a short comment on its
O(n) complexity and when it is acceptable, and optionally refactor later to use
a HashSet<(Type handlerInterface, Type implementationType)> for O(1) membership
checks if registration performance becomes an issue; reference the
IsHandlerMappingAlreadyRegistered method and the
IServiceCollection/descriptor.ServiceType and descriptor.ImplementationType
comparisons when making the note or future change.
🤖 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.Cqrs/Internal/CqrsHandlerRegistrar.cs`:
- Around line 234-242: The IsHandlerMappingAlreadyRegistered method currently
does a linear Any scan over IServiceCollection for each handler mapping which is
O(n) per check and can lead to O(n²) behavior at scale; update the code by
adding a short comment on its O(n) complexity and when it is acceptable, and
optionally refactor later to use a HashSet<(Type handlerInterface, Type
implementationType)> for O(1) membership checks if registration performance
becomes an issue; reference the IsHandlerMappingAlreadyRegistered method and the
IServiceCollection/descriptor.ServiceType and descriptor.ImplementationType
comparisons when making the note or future change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ea42b19a-cbf6-4634-9a04-d425e27a5f8e

📥 Commits

Reviewing files that changed from the base of the PR and between a7604de and bc93364.

📒 Files selected for processing (5)
  • GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.cs
  • GFramework.Cqrs/CqrsReflectionFallbackAttribute.cs
  • GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs
  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
✅ Files skipped from review due to trivial changes (1)
  • GFramework.Cqrs/CqrsReflectionFallbackAttribute.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.Cqrs/Internal/CqrsHandlerRegistrar.cs
  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.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.Cqrs/Internal/CqrsHandlerRegistrar.cs
  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.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)
📚 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.Cqrs/Internal/CqrsHandlerRegistrar.cs
  • 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 : Avoid hidden side effects in property getters, constructors, and registration helpers

Applied to files:

  • GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.cs
  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
📚 Learning: 2026-04-05T15:30:46.211Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-05T15:30:46.211Z
Learning: Use MicrosoftDiContainer wrapping Microsoft.Extensions.DependencyInjection for unified component registration and service resolution

Applied to files:

  • GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.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.Cqrs/Internal/CqrsHandlerRegistrar.cs
  • GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs
  • GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.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 : 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.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.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.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.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.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.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 : 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
📚 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 : Regression fixes should include a test that fails before the fix and passes after it

Applied to files:

  • GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
🪛 GitHub Check: Build and Test
GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs

[failure] 52-52:
The type or namespace name 'Assembly' could not be found (are you missing a using directive or an assembly reference?)


[failure] 52-52:
The type or namespace name 'Assembly' could not be found (are you missing a using directive or an assembly reference?)


[failure] 226-226:
The type or namespace name 'Assembly' could not be found (are you missing a using directive or an assembly reference?)

🔇 Additional comments (16)
GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs (4)

34-41: LGTM!

从布尔值转换为 GeneratedRegistrationResult 枚举使控制流更加清晰。仅当结果为 FullyHandled 时才跳过反射扫描,这与预期行为一致。


105-112: LGTM!

在成功执行生成注册器后检查 RequiresReflectionFallback 属性的逻辑正确。这确保了生成注册器先完成注册,再决定是否需要补充反射扫描。


260-265: LGTM!

GeneratedRegistrationResult 枚举设计清晰,三个状态完整覆盖了生成注册器的所有可能结果。作为私有枚举,其可见性范围恰当。


1-5: System.Reflection 已通过 GlobalUsings.cs 全局提供,无需添加显式 using 指令。

GFramework.Cqrs/GlobalUsings.cs 已在第 6 行包含 global using System.Reflection;,项目中所有文件都可以访问此命名空间。不存在构建失败问题。

			> Likely an incorrect or invalid review comment.
GFramework.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs (5)

49-63: LGTM!

CreateGenerationEnvironment 方法正确检测编译环境中的所有必要类型,包括新增的 CqrsReflectionFallbackAttribute。使用 readonly record struct 确保了生成器的增量缓存友好性和确定性。


127-137: LGTM!

控制流逻辑清晰:

  1. 无注册项时立即返回
  2. 当运行时合同不支持反射回退标记时,保留原有的全有或全无行为
  3. 正确传递 hasUnsupportedConcreteHandler 以控制是否发射回退属性

这确保了与旧版运行时的向后兼容性。


156-163: LGTM!

return 改为 continue 是启用部分生成的关键变更。遇到不可引用的处理器时,生成器会设置标志并继续收集其余有效注册项,而非放弃整个程序集。


300-305: LGTM!

条件性地发射 [assembly: CqrsReflectionFallbackAttribute()] 的逻辑正确。仅当存在不可由生成代码引用的处理器时才添加此属性,与运行时的反射回退机制配合良好。


424-426: LGTM!

GenerationEnvironment 使用 readonly record struct 是增量生成器的最佳实践,确保了值语义和高效的相等性比较,有利于生成器缓存。

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

64-68: LGTM!

在测试输入中添加 CqrsReflectionFallbackAttribute 定义是必要的,这使得生成器能够检测到运行时合同支持反射回退标记。由于此测试场景中所有处理器都是可见的,生成输出正确地不包含该属性。


131-234: LGTM!

此测试完整验证了新的部分生成行为:

  1. 输入包含可见处理器和私有嵌套处理器
  2. 预期输出仅包含可见处理器的注册
  3. 预期输出包含 [assembly: CqrsReflectionFallbackAttribute()] 以触发运行时反射补扫

测试设计与生成器实现逻辑一致。


236-316: LGTM!

测试重命名准确反映了新语义:当运行时合同中不存在反射回退标记属性时,生成器保留原有的全有或全无行为,避免静默丢失不可见处理器。这确保了与旧版运行时的向后兼容性。

GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.cs (4)

16-17: LGTM!

将字段改为可空类型是合理的,因为 SetUpTearDown 方法分别初始化和清理这些字段。


196-234: LGTM!

此测试完整验证了"生成注册器 + 反射回退"的组合路径:

  1. 模拟程序集同时提供 CqrsHandlerRegistryAttributeCqrsReflectionFallbackAttribute
  2. GetTypes() 返回生成路径和反射路径的处理器
  3. 断言验证最终注册中包含两个不同实现且无重复

测试直接检查 GetServicesUnsafe 而非调用 Freeze() 后解析,这更精确地验证了去重逻辑。


385-409: LGTM!

ReflectionFallbackNotificationContainer 巧妙地模拟了真实场景:生成代码无法引用私有嵌套类型,但运行时反射可以发现并注册它们。通过 ReflectionOnlyHandlerType 属性暴露类型供测试使用。


411-432: LGTM!

PartialGeneratedNotificationHandlerRegistry 正确模拟了局部生成注册器的行为:仅注册生成代码可直接引用的处理器,将剩余处理器留给反射补扫。与 ReflectionFallbackNotificationContainer 配合,完整验证了组合注册路径。

- 实现MicrosoftDiContainer类作为IIocContainer接口的适配器
- 提供线程安全的依赖注入容器功能
- 支持单例、瞬态、作用域服务注册
- 实现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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
GFramework.Core/Ioc/MicrosoftDiContainer.cs (1)

403-411: ⚠️ Potential issue | 🟡 Minor

先固定并校验 assemblies,再下发到注册服务。

这里仅校验了枚举本身非空,但没有校验元素,也没有把延迟枚举固定下来。后续注册服务会基于这些程序集做反射/注册;如果调用方传入包含 null 的集合,或传入依赖可变外部状态的延迟枚举,异常会在更深层才暴露,且这里也失去了对注册顺序的显式控制。建议先 ToArray(),再逐项 ThrowIfNull 后再委托。

💡建议修改
 public void RegisterCqrsHandlersFromAssemblies(IEnumerable<Assembly> assemblies)
 {
     ArgumentNullException.ThrowIfNull(assemblies);
+    var assemblyArray = assemblies.ToArray();
+    foreach (var assembly in assemblyArray)
+    {
+        ArgumentNullException.ThrowIfNull(assembly);
+    }
 
     _lock.EnterWriteLock();
     try
     {
         ThrowIfFrozen();
-        ResolveCqrsRegistrationService().RegisterHandlers(assemblies);
+        ResolveCqrsRegistrationService().RegisterHandlers(assemblyArray);
     }
     finally
As per coding guidelines, "Preserve deterministic behavior in registries, lifecycle orchestration, and generated outputs" and "Validate external or user-controlled input before it reaches file system, serialization, reflection, code generation, or process boundaries".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.Core/Ioc/MicrosoftDiContainer.cs` around lines 403 - 411, The
method RegisterCqrsHandlersFromAssemblies currently only checks the assemblies
enumerable for null but doesn't materialize it or validate individual entries;
change it to materialize the sequence (e.g., call ToArray on assemblies), then
validate each element for null (throw if any null), and only after that acquire
_lock, call ThrowIfFrozen(), and pass the validated, ordered array to
ResolveCqrsRegistrationService().RegisterHandlers so registration sees a
deterministic, non-null set of assemblies.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@GFramework.Core/Ioc/MicrosoftDiContainer.cs`:
- Around line 403-411: The method RegisterCqrsHandlersFromAssemblies currently
only checks the assemblies enumerable for null but doesn't materialize it or
validate individual entries; change it to materialize the sequence (e.g., call
ToArray on assemblies), then validate each element for null (throw if any null),
and only after that acquire _lock, call ThrowIfFrozen(), and pass the validated,
ordered array to ResolveCqrsRegistrationService().RegisterHandlers so
registration sees a deterministic, non-null set of assemblies.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4067fe8c-4b1c-4e12-9cc3-980e31c76fb6

📥 Commits

Reviewing files that changed from the base of the PR and between 00a1038 and 0d9d09b.

📒 Files selected for processing (5)
  • GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs
  • GFramework.Core/Ioc/MicrosoftDiContainer.cs
  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs
  • GFramework.Cqrs/Internal/DefaultCqrsRegistrationService.cs
✅ Files skipped from review due to trivial changes (3)
  • GFramework.Cqrs/Internal/DefaultCqrsRegistrationService.cs
  • GFramework.Cqrs.Abstractions/Cqrs/ICqrsRuntime.cs
  • GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.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 (2)
**/*.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.Core/Ioc/MicrosoftDiContainer.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.Core/Ioc/MicrosoftDiContainer.cs
🧠 Learnings (5)
📚 Learning: 2026-04-05T15:30:46.211Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-05T15:30:46.211Z
Learning: Use MicrosoftDiContainer wrapping Microsoft.Extensions.DependencyInjection for unified component registration and service resolution

Applied to files:

  • GFramework.Core/Ioc/MicrosoftDiContainer.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.Core/Ioc/MicrosoftDiContainer.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 : Preserve deterministic behavior in registries, lifecycle orchestration, and generated outputs

Applied to files:

  • GFramework.Core/Ioc/MicrosoftDiContainer.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.Core/Ioc/MicrosoftDiContainer.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 : Use the namespace pattern `GFramework.{Module}.{Feature}` with PascalCase segments

Applied to files:

  • GFramework.Core/Ioc/MicrosoftDiContainer.cs
🔇 Additional comments (4)
GFramework.Core/Ioc/MicrosoftDiContainer.cs (4)

38-45: 这个辅助分组类型抽得合适。

把可见服务类型、出现次数和稳定 tie-break 所需的数据收拢到 VisibleServiceTypeGroup 后,后面的选择逻辑可读性明显更好了。


441-459: 这里的失败路径更清晰了。

直接解析 ICqrsRegistrationService 并给出明确错误信息后,CQRS 模块未安装或安装顺序不对时,定位会容易很多。


597-633: 未冻结 GetAll 的入口现在统一了。

GetAll<T>()GetAll(Type) 共用了同一套未冻结收集逻辑,而且给 GetAll(Type) 补上了空值保护,后续维护成本会低不少。


645-745: 这套别名去重策略写得比较稳。

按实例分组、优先保留精确请求类型、再按注册次数和首次出现顺序稳定打破并列,既避免了同一实例因别名重复返回,也保留了同一服务类型的重复显式注册语义。

As per coding guidelines, "Methods with non-trivial logic MUST document the core idea, key decisions, and edge case handling" and "Preserve deterministic behavior in registries, lifecycle orchestration, and generated outputs".

- 实现MicrosoftDiContainer类,包装IServiceProvider为IIocContainer接口
- 提供线程安全的依赖注入容器功能,支持单例、瞬态、作用域服务注册
- 添加RegisterSingleton、RegisterTransient、RegisterScoped等多种注册方法
- 实现RegisterPlurality方法支持一个实例注册到多个接口类型
- 添加CQRS相关注册功能,包括管道行为和处理器自动注册
- 实现Get、GetAll、GetRequired等服务解析方法
- 添加容器冻结机制,冻结后构建ServiceProvider提供服务解析
- 实现CreateScope方法支持服务作用域创建
- 添加完整的单元测试覆盖各种注册和解析场景
- 实现服务按优先级排序功能支持系统调度需求
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

🤖 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.Core/Ioc/MicrosoftDiContainer.cs`:
- Around line 454-465: ResolveCqrsRegistrationService currently only accepts a
descriptor with an ImplementationInstance and treats any other registration as
"not registered"; update the method so if a descriptor exists but
descriptor.ImplementationInstance is null it throws a more specific
InvalidOperationException (and logs) that states ICqrsRegistrationService must
be registered as an instance (e.g. via CqrsRuntimeModule or RegisterSingleton
with an instance) and that other registration forms (factory/type) are
unsupported, and keep the original "not registered" message only when no
descriptor is found; reference ResolveCqrsRegistrationService,
ICqrsRegistrationService, GetServicesUnsafe and CqrsRuntimeModule in the message
to guide callers.
🪄 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: e8babec8-4328-4915-b9b6-cf18af00e73c

📥 Commits

Reviewing files that changed from the base of the PR and between 0d9d09b and a4dfc78.

📒 Files selected for processing (2)
  • GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs
  • GFramework.Core/Ioc/MicrosoftDiContainer.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.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). (3)
  • GitHub Check: Analyze (C#)
  • GitHub Check: Build and Test
  • GitHub Check: Code Quality & Security
🧰 Additional context used
📓 Path-based instructions (2)
**/*.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.Core/Ioc/MicrosoftDiContainer.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.Core/Ioc/MicrosoftDiContainer.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-05T15:30:46.211Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-05T15:30:46.211Z
Learning: Use MicrosoftDiContainer wrapping Microsoft.Extensions.DependencyInjection for unified component registration and service resolution

Applied to files:

  • GFramework.Core/Ioc/MicrosoftDiContainer.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.Core/Ioc/MicrosoftDiContainer.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 : Use the namespace pattern `GFramework.{Module}.{Feature}` with PascalCase segments

Applied to files:

  • GFramework.Core/Ioc/MicrosoftDiContainer.cs
🔇 Additional comments (2)
GFramework.Core/Ioc/MicrosoftDiContainer.cs (2)

404-417: 前置校验补得很对。

这里先把 IEnumerable<Assembly> 物化并逐项做空值校验,能把坏输入挡在容器边界之外,后面的批量注册路径也更干净。


651-751: 未冻结态别名去重规则写得很清楚。

requestedServiceType 优先、其次按分组数量和首次出现顺序稳定打破并列,这个选择规则既可预测,也和注释保持一致,后续排查 GetAll* 行为会轻松很多。

Comment on lines +454 to 465
private ICqrsRegistrationService ResolveCqrsRegistrationService()
{
var descriptor = GetServicesUnsafe.LastOrDefault(static service =>
service.ServiceType == typeof(ICqrsHandlerRegistrar));
service.ServiceType == typeof(ICqrsRegistrationService));

if (descriptor?.ImplementationInstance is ICqrsHandlerRegistrar registrar)
return registrar;
if (descriptor?.ImplementationInstance is ICqrsRegistrationService registrationService)
return registrationService;

const string errorMessage =
"ICqrsHandlerRegistrar not registered. Ensure the CQRS runtime module has been installed before registering handlers.";
"ICqrsRegistrationService not registered. Ensure the CQRS runtime module has been installed before registering handlers.";
_logger.Error(errorMessage);
throw new InvalidOperationException(errorMessage);
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== 查找 ICqrsRegistrationService 的注册位置 =="
rg -n -C3 --type=cs '\bICqrsRegistrationService\b'

echo
echo "== 查找可能产生 ImplementationType / ImplementationFactory 的注册方式 =="
rg -n -C3 --type=cs \
  'RegisterSingleton<\s*ICqrsRegistrationService\s*,|RegisterFactory<\s*ICqrsRegistrationService\s*>\s*\(|AddSingleton<\s*ICqrsRegistrationService\s*,|AddSingleton\s*\(\s*typeof\s*\(\s*ICqrsRegistrationService\s*\)'

echo
echo "== 查找实例注册路径 =="
rg -n -C3 --type=cs \
  'CreateRegistrationService\s*\(|Register\s*\(\s*typeof\s*\(\s*ICqrsRegistrationService\s*\)|RegisterSingleton\s*\(\s*.*ICqrsRegistrationService'

Repository: GeWuYou/GFramework

Length of output: 5601


🏁 Script executed:

# 查看 MicrosoftDiContainer 类的 Register 方法签名
rg -n -A5 'public.*Register<' GFramework.Core/Ioc/MicrosoftDiContainer.cs | head -80

Repository: GeWuYou/GFramework

Length of output: 214


🏁 Script executed:

# 查看是否有 RegisterSingleton 或 RegisterFactory 的公开方法
rg -n 'public.*Register(Singleton|Factory)' GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 217


🏁 Script executed:

# 查看整个 MicrosoftDiContainer 类以了解其 API
wc -l GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 109


🏁 Script executed:

# 查看 RegisterSingleton<TService, TImpl> 的实现
sed -n '116,130p' GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 493


🏁 Script executed:

# 查看 RegisterFactory<TService> 的实现
sed -n '305,325p' GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 549


🏁 Script executed:

# 查看容器如何解析服务(Get/GetRequired 方法)
rg -n -A10 'public.*Get<TService>\(|public.*GetRequired<TService>\(' GFramework.Core/Ioc/MicrosoftDiContainer.cs | head -50

Repository: GeWuYou/GFramework

Length of output: 44


🏁 Script executed:

# 查看 Get 和 GetRequired 方法
rg -n -B2 -A15 'public.*TService\?.*Get<TService>\(|public.*GetRequired<TService>\(' GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 44


🏁 Script executed:

# 查找 ResolveCqrsRegistrationService 的调用点
rg -n 'ResolveCqrsRegistrationService' GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 217


🏁 Script executed:

# 查看 ResolveCqrsRegistrationService 被调用的上下文
rg -n -B5 -A2 'ResolveCqrsRegistrationService\(\)' GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 711


🏁 Script executed:

# 查看 Get/GetRequired 完整实现,使用 sed 查看具体行号
sed -n '350,400p' GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 2050


🏁 Script executed:

# 查看注册 ICqrsRegistrationService 的所有位置和方式
rg -n -B3 -A3 'Register.*ICqrsRegistrationService' GFramework.Core/

Repository: GeWuYou/GFramework

Length of output: 787


🏁 Script executed:

# 检查是否有其他使用 RegisterSingleton<T, TImpl> 的例子来理解是否允许这样做
rg -n 'RegisterSingleton<.*,.*>' GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 118


🏁 Script executed:

# 查看 RegisterCqrsHandlersFromAssemblies 的上下文和完整注释
sed -n '408,425p' GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 454


🏁 Script executed:

# 查看注释中关于"实例绑定"的部分
sed -n '445,455p' GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 455


🏁 Script executed:

# 确认一下 Get 方法的完整实现,查看它如何处理不同类型的描述符
rg -n -A30 'public.*\?.*Get<TService>' GFramework.Core/Ioc/MicrosoftDiContainer.cs | head -60

Repository: GeWuYou/GFramework

Length of output: 44


🏁 Script executed:

# 查看容器的公开 Register 方法的 XML 文档注释
sed -n '255,275p' GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 678


🏁 Script executed:

# 查看 RegisterSingleton<TService, TImpl> 的 XML 文档注释
sed -n '105,120p' GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 483


🏁 Script executed:

# 查看 RegisterFactory 的 XML 文档注释
sed -n '295,315p' GFramework.Core/Ioc/MicrosoftDiContainer.cs

Repository: GeWuYou/GFramework

Length of output: 621


🏁 Script executed:

# 查看 CqrsRuntimeModule 的完整上下文,看它如何安装
sed -n '30,55p' GFramework.Core/Services/Modules/CqrsRuntimeModule.cs

Repository: GeWuYou/GFramework

Length of output: 1210


ResolveCqrsRegistrationService() 只检查实例绑定,但容器公开 API 允许其他注册方式。

容器支持 RegisterSingleton<TService, TImpl>()RegisterFactory<TService>() 作为公开 API,但此方法仅检查 descriptor?.ImplementationInstance。如果用户通过这些 API 注册 ICqrsRegistrationService(即使是合法的用法),也会触发"not registered"错误。

虽然当前官方模块(CqrsRuntimeModule)只用实例方式注册,注释也说明了这是有意的设计(避免在容器未冻结时完整构建),但这个约束应该更显式地防守或文档化。建议:

  1. 在方法中添加 null 检查和更具体的错误消息,说明只支持实例注册
  2. 或在 CqrsRuntimeModule 和相关文档中明确标注 ICqrsRegistrationService 只能通过实例注册
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.Core/Ioc/MicrosoftDiContainer.cs` around lines 454 - 465,
ResolveCqrsRegistrationService currently only accepts a descriptor with an
ImplementationInstance and treats any other registration as "not registered";
update the method so if a descriptor exists but
descriptor.ImplementationInstance is null it throws a more specific
InvalidOperationException (and logs) that states ICqrsRegistrationService must
be registered as an instance (e.g. via CqrsRuntimeModule or RegisterSingleton
with an instance) and that other registration forms (factory/type) are
unsupported, and keep the original "not registered" message only when no
descriptor is found; reference ResolveCqrsRegistrationService,
ICqrsRegistrationService, GetServicesUnsafe and CqrsRuntimeModule in the message
to guide callers.

@GeWuYou GeWuYou merged commit 21627c0 into refactor/cqrs-architecture-decoupling Apr 16, 2026
7 checks passed
@GeWuYou GeWuYou deleted the refactor/cqrs-architecture-decoupling-todo-7 branch April 16, 2026 01:57
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