Skip to content

Feature/context enhancement#63

Merged
GeWuYou merged 4 commits into
mainfrom
feature/context-enhancement
Mar 2, 2026
Merged

Feature/context enhancement#63
GeWuYou merged 4 commits into
mainfrom
feature/context-enhancement

Conversation

@GeWuYou

@GeWuYou GeWuYou commented Mar 1, 2026

Copy link
Copy Markdown
Owner

Summary by Sourcery

引入用于提供架构上下文的抽象,并将其集成到具备上下文感知的代码生成中,同时新增用于注册表初始化的基础设施及相应测试。

New Features:

  • 添加 IArchitectureContextProvider 接口,以及默认实现 GameContextProviderScopedContextProvider,用于获取架构上下文。
  • 引入 RegistryInitializationHookBase,以便在特定架构生命周期阶段,将配置项注册到各类工具中,从而简化注册流程。

Enhancements:

  • 更新 ContextAware 源代码生成器,通过可配置的 provider hook 使用 IArchitectureContextProvider 来解析 Context 属性。
  • 允许重写 TestArchitectureContext.GetUtility,以在新测试中支持自定义测试上下文。

Tests:

  • RegistryInitializationHookBase 添加单元测试,覆盖阶段行为、缺失注册表、空配置以及重复调用等情况。
  • GameContextProviderScopedContextProvider 添加单元测试,以验证上下文获取和类型安全查找行为。
  • 更新源代码生成器的快照测试,以适配基于新上下文提供程序的 API。
Original summary in English

Summary by Sourcery

Introduce an abstraction for providing architecture contexts and integrate it into context-aware code generation, along with new infrastructure for registry initialization and corresponding tests.

New Features:

  • Add IArchitectureContextProvider interface and default GameContextProvider and ScopedContextProvider implementations for retrieving architecture contexts.
  • Introduce RegistryInitializationHookBase to streamline registering configuration items into utilities during specific architecture lifecycle phases.

Enhancements:

  • Update the ContextAware source generator to resolve the Context property via an IArchitectureContextProvider with a configurable provider hook.
  • Allow TestArchitectureContext.GetUtility to be overridden to support custom test contexts in new tests.

Tests:

  • Add unit tests for RegistryInitializationHookBase covering phase behavior, missing registries, empty configs, and repeated invocations.
  • Add unit tests for GameContextProvider and ScopedContextProvider to verify context retrieval and type-safe lookup behavior.
  • Update source generator snapshot tests to account for the new context provider-based API.

- 引入 IArchitectureContextProvider 接口解耦上下文获取逻辑
- 创建 GameContextProvider 作为默认上下文提供者
- 添加 ScopedContextProvider 支持多架构实例场景
- 修改源代码生成器使用上下文提供者模式
- 增加 SetContextProvider 方法支持测试和多架构场景
- 添加 RegistryInitializationHookBase 简化注册表初始化逻辑
- 新增 IArchitectureContextProvider 接口定义
- 实现 GameContextProvider 类提供上下文获取功能
- 添加 GameContext 静态类用于获取架构上下文
- 创建 ContextProviderTests 测试上下文提供者功能
- 实现 RegistryInitializationHookBase 抽象基类的完整测试
- 修改 IArchitectureContext.GetUtility 方法为虚拟方法以支持重写
@sourcery-ai

sourcery-ai Bot commented Mar 1, 2026

Copy link
Copy Markdown

审阅者指南

引入了可插拔的架构上下文提供者抽象及其默认实现;更新源码生成器以使用该提供者而不是直接访问 GameContext;并新增了可复用的注册表初始化生命周期钩子,同时为新行为补充了完整的单元测试。

使用 IArchitectureContextProvider 生成的 Context 属性的时序图

sequenceDiagram
    actor Caller
    participant GeneratedType as GeneratedContextAwareType
    participant Provider as IArchitectureContextProvider
    participant GameContextProvider
    participant GameContext
    participant Ctx as IArchitectureContext

    Caller->>GeneratedType: access Context
    alt _context is null
        GeneratedType->>GeneratedType: check _context
        alt _contextProvider is null
            GeneratedType->>GameContextProvider: new GameContextProvider()
            GeneratedType->>GeneratedType: assign _contextProvider
        end
        GeneratedType->>Provider: GetContext()
        Provider->>GameContextProvider: GetContext()
        GameContextProvider->>GameContext: GetFirstArchitectureContext()
        GameContext-->>GameContextProvider: Ctx
        GameContextProvider-->>GeneratedType: Ctx
        GeneratedType->>GeneratedType: cache Ctx in _context
    end
    GeneratedType-->>Caller: Ctx
Loading

RegistryInitializationHookBase.OnPhase 行为的时序图

sequenceDiagram
    participant Hook as RegistryInitializationHookBase
    participant Arch as IArchitecture
    participant Ctx as IArchitectureContext
    participant Registry as TRegistry

    Arch->>Hook: OnPhase(phase, architecture)
    alt phase != targetPhase
        Hook-->>Arch: return
    else phase == targetPhase
        Hook->>Arch: get Context
        Arch-->>Hook: Ctx
        Hook->>Ctx: GetUtility_TRegistry_()
        alt registry not found
            Ctx-->>Hook: null
            Hook-->>Arch: return
        else registry found
            Ctx-->>Hook: Registry
            loop for each config in _configs
                Hook->>Hook: RegisterConfig(Registry, config)
            end
            Hook-->>Arch: return
        end
    end
Loading

架构上下文提供者抽象及其用法的类图

classDiagram
    class IArchitectureContext

    class IArchitectureContextProvider {
        +IArchitectureContext GetContext()
        +bool TryGetContext_T_(out T context)
    }

    class GameContextProvider {
        +IArchitectureContext GetContext()
        +bool TryGetContext_T_(out T context)
    }

    class ScopedContextProvider {
        -IArchitectureContext _context
        +ScopedContextProvider(IArchitectureContext context)
        +IArchitectureContext GetContext()
        +bool TryGetContext_T_(out T context)
    }

    class GameContext {
        +IArchitectureContext GetFirstArchitectureContext()
        +bool TryGet_T_(out T context)
        +void Bind(System_Type type, IArchitectureContext context)
        +void Clear()
    }

    class GeneratedContextAwareType {
        -IArchitectureContext _context
        -static IArchitectureContextProvider _contextProvider
        +IArchitectureContext Context
        +static void SetContextProvider(IArchitectureContextProvider provider)
    }

    IArchitectureContextProvider <|.. GameContextProvider
    IArchitectureContextProvider <|.. ScopedContextProvider
    GameContextProvider ..> GameContext
    ScopedContextProvider o-- IArchitectureContext
    GeneratedContextAwareType --> IArchitectureContextProvider
    GeneratedContextAwareType --> IArchitectureContext
Loading

RegistryInitializationHookBase 及测试脚手架的类图

classDiagram
    class IArchitectureLifecycleHook {
        +void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
    }

    class IArchitecture {
        +IArchitectureContext Context
    }

    class IArchitectureContext {
        +TUtility GetUtility_TUtility_()
    }

    class IUtility

    class ArchitecturePhase

    class RegistryInitializationHookBase_TRegistry_TConfig_ {
        -IEnumerable_TConfig_ _configs
        -ArchitecturePhase _targetPhase
        +RegistryInitializationHookBase_TRegistry_TConfig_(IEnumerable_TConfig_ configs, ArchitecturePhase targetPhase)
        +void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
        #void RegisterConfig(TRegistry registry, TConfig config)
    }

    class TestRegistryInitializationHook {
        +TestRegistryInitializationHook(IEnumerable_string_ configs, ArchitecturePhase targetPhase)
        +void RegisterConfig(TestRegistry registry, string config)
    }

    class TestRegistry {
        +List_string_ RegisteredConfigs
        +void Register(string config)
    }

    class TestArchitectureContext {
        +virtual TUtility GetUtility_TUtility_()
    }

    class TestArchitectureContextWithRegistry {
        -TestRegistry _registry
        +TestArchitectureContextWithRegistry(TestRegistry registry)
        +override TUtility GetUtility_TUtility_()
    }

    class TestArchitectureWithRegistry {
        -TestRegistry _registry
        +IArchitectureContext Context
    }

    class TestArchitectureWithoutRegistry {
        +IArchitectureContext Context
    }

    IArchitectureLifecycleHook <|.. RegistryInitializationHookBase_TRegistry_TConfig_
    RegistryInitializationHookBase_TRegistry_TConfig_ ..> IArchitectureContext
    RegistryInitializationHookBase_TRegistry_TConfig_ ..> IArchitecture
    RegistryInitializationHookBase_TRegistry_TConfig_ ..> ArchitecturePhase
    RegistryInitializationHookBase_TRegistry_TConfig_ ..> IUtility

    RegistryInitializationHookBase_TRegistry_TConfig_ <|-- TestRegistryInitializationHook

    TestRegistry ..|> IUtility

    TestArchitectureWithRegistry ..|> IArchitecture
    TestArchitectureWithoutRegistry ..|> IArchitecture

    TestArchitectureContextWithRegistry --|> TestArchitectureContext
    TestArchitectureContext ..|> IArchitectureContext

    TestArchitectureWithRegistry o-- TestArchitectureContextWithRegistry
    TestArchitectureContextWithRegistry o-- TestRegistry
    TestArchitectureWithRegistry o-- TestRegistry
Loading

文件级变更

变更 详情 文件
引入 IArchitectureContextProvider 抽象以及全局和作用域上下文的具体提供者,并将它们接入支持上下文感知的源码生成器。
  • 添加 IArchitectureContextProvider 接口,定义 GetContext 和泛型 TryGetContext 方法,用于解耦上下文获取逻辑。
  • 实现 GameContextProvider,通过 GameContext.GetFirstArchitectureContextGameContext.TryGet 来进行默认/全局上下文解析。
  • 实现 ScopedContextProvider,包装特定的 IArchitectureContext 实例,并通过模式匹配支持类型化获取。
  • 更新 ContextAwareGenerator,持有一个静态 IArchitectureContextProvider,按需以 GameContextProvider 懒加载初始化,并暴露静态 SetContextProvider 方法,以便在测试或多架构场景中进行覆写。
  • 调整 ContextAwareGeneratorSnapshotTests 中的测试快照,以反映新的接口、提供者实现以及修改后的 GameContext 结构。
GFramework.Core.Abstractions/architecture/IArchitectureContextProvider.cs
GFramework.Core/architecture/GameContextProvider.cs
GFramework.Core/architecture/ScopedContextProvider.cs
GFramework.SourceGenerators/rule/ContextAwareGenerator.cs
GFramework.SourceGenerators.Tests/rule/ContextAwareGeneratorSnapshotTests.cs
GFramework.Core.Tests/architecture/ContextProviderTests.cs
添加通用的 RegistryInitializationHookBase 生命周期钩子,以简化基于注册表的配置初始化,并为其编写测试用例。
  • 创建抽象类 RegistryInitializationHookBase<TRegistry,TConfig>,实现 IArchitectureLifecycleHook,并以注册表类型和配置类型为泛型参数。
  • 保存一个配置集合和目标 ArchitecturePhase,默认值为 AfterSystemInit;在 OnPhase 中从 architecture.Context 获取注册表,并为每个配置执行注册。
  • 定义抽象方法 RegisterConfig,由子类实现具体的注册逻辑。
  • 新增 RegistryInitializationHookBaseTests,包含具体实现 TestRegistryInitializationHookTestRegistry 工具类,以及架构/上下文测试替身,用于验证跨阶段、缺失注册表、空配置和重复调用等场景下的行为。
  • TestArchitectureContext.GetUtility 设为 virtual,以便在新测试使用的派生测试上下文中进行重写。
GFramework.Core/architecture/RegistryInitializationHookBase.cs
GFramework.Core.Tests/architecture/RegistryInitializationHookBaseTests.cs
GFramework.Core.Tests/architecture/GameContextTests.cs

技巧与命令

与 Sourcery 交互

  • 触发新审查: 在 Pull Request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 在审查评论下回复,要求 Sourcery 根据该评论创建 issue。你也可以在审查评论下回复 @sourcery-ai issue,从该评论创建一个 issue。
  • 生成 Pull Request 标题: 在 Pull Request 标题的任意位置写上 @sourcery-ai,即可随时生成标题。你也可以在 Pull Request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 Pull Request 摘要: 在 Pull Request 正文中任意位置写上 @sourcery-ai summary,即可在该位置生成 PR 摘要。你也可以在 Pull Request 中评论 @sourcery-ai summary 来(重新)生成摘要。
  • 生成审阅者指南: 在 Pull Request 中评论 @sourcery-ai guide,即可(重新)生成审阅者指南。
  • 解决所有 Sourcery 评论: 在 Pull Request 中评论 @sourcery-ai resolve,即可将所有 Sourcery 评论标记为已解决。如果你已经处理了所有评论且不希望再看到它们,这会很有用。
  • 撤销所有 Sourcery 审查: 在 Pull Request 中评论 @sourcery-ai dismiss,即可撤销所有现有的 Sourcery 审查。特别适用于你希望以新的审查重新开始的场景——别忘了随后评论 @sourcery-ai review 以触发新的审查!

自定义你的体验

访问你的 控制面板 以:

  • 启用或禁用审查功能,例如 Sourcery 自动生成的 Pull Request 摘要、审阅者指南等。
  • 更改审查语言。
  • 添加、移除或编辑自定义审查指令。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

Introduces a pluggable architecture context provider abstraction and default implementations, updates the source generator to use it instead of accessing GameContext directly, and adds a reusable registry-initialization lifecycle hook with comprehensive unit tests for the new behavior.

Sequence diagram for generated Context property using IArchitectureContextProvider

sequenceDiagram
    actor Caller
    participant GeneratedType as GeneratedContextAwareType
    participant Provider as IArchitectureContextProvider
    participant GameContextProvider
    participant GameContext
    participant Ctx as IArchitectureContext

    Caller->>GeneratedType: access Context
    alt _context is null
        GeneratedType->>GeneratedType: check _context
        alt _contextProvider is null
            GeneratedType->>GameContextProvider: new GameContextProvider()
            GeneratedType->>GeneratedType: assign _contextProvider
        end
        GeneratedType->>Provider: GetContext()
        Provider->>GameContextProvider: GetContext()
        GameContextProvider->>GameContext: GetFirstArchitectureContext()
        GameContext-->>GameContextProvider: Ctx
        GameContextProvider-->>GeneratedType: Ctx
        GeneratedType->>GeneratedType: cache Ctx in _context
    end
    GeneratedType-->>Caller: Ctx
Loading

Sequence diagram for RegistryInitializationHookBase.OnPhase behavior

sequenceDiagram
    participant Hook as RegistryInitializationHookBase
    participant Arch as IArchitecture
    participant Ctx as IArchitectureContext
    participant Registry as TRegistry

    Arch->>Hook: OnPhase(phase, architecture)
    alt phase != targetPhase
        Hook-->>Arch: return
    else phase == targetPhase
        Hook->>Arch: get Context
        Arch-->>Hook: Ctx
        Hook->>Ctx: GetUtility_TRegistry_()
        alt registry not found
            Ctx-->>Hook: null
            Hook-->>Arch: return
        else registry found
            Ctx-->>Hook: Registry
            loop for each config in _configs
                Hook->>Hook: RegisterConfig(Registry, config)
            end
            Hook-->>Arch: return
        end
    end
Loading

Class diagram for architecture context provider abstraction and usage

classDiagram
    class IArchitectureContext

    class IArchitectureContextProvider {
        +IArchitectureContext GetContext()
        +bool TryGetContext_T_(out T context)
    }

    class GameContextProvider {
        +IArchitectureContext GetContext()
        +bool TryGetContext_T_(out T context)
    }

    class ScopedContextProvider {
        -IArchitectureContext _context
        +ScopedContextProvider(IArchitectureContext context)
        +IArchitectureContext GetContext()
        +bool TryGetContext_T_(out T context)
    }

    class GameContext {
        +IArchitectureContext GetFirstArchitectureContext()
        +bool TryGet_T_(out T context)
        +void Bind(System_Type type, IArchitectureContext context)
        +void Clear()
    }

    class GeneratedContextAwareType {
        -IArchitectureContext _context
        -static IArchitectureContextProvider _contextProvider
        +IArchitectureContext Context
        +static void SetContextProvider(IArchitectureContextProvider provider)
    }

    IArchitectureContextProvider <|.. GameContextProvider
    IArchitectureContextProvider <|.. ScopedContextProvider
    GameContextProvider ..> GameContext
    ScopedContextProvider o-- IArchitectureContext
    GeneratedContextAwareType --> IArchitectureContextProvider
    GeneratedContextAwareType --> IArchitectureContext
Loading

Class diagram for RegistryInitializationHookBase and test scaffolding

classDiagram
    class IArchitectureLifecycleHook {
        +void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
    }

    class IArchitecture {
        +IArchitectureContext Context
    }

    class IArchitectureContext {
        +TUtility GetUtility_TUtility_()
    }

    class IUtility

    class ArchitecturePhase

    class RegistryInitializationHookBase_TRegistry_TConfig_ {
        -IEnumerable_TConfig_ _configs
        -ArchitecturePhase _targetPhase
        +RegistryInitializationHookBase_TRegistry_TConfig_(IEnumerable_TConfig_ configs, ArchitecturePhase targetPhase)
        +void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
        #void RegisterConfig(TRegistry registry, TConfig config)
    }

    class TestRegistryInitializationHook {
        +TestRegistryInitializationHook(IEnumerable_string_ configs, ArchitecturePhase targetPhase)
        +void RegisterConfig(TestRegistry registry, string config)
    }

    class TestRegistry {
        +List_string_ RegisteredConfigs
        +void Register(string config)
    }

    class TestArchitectureContext {
        +virtual TUtility GetUtility_TUtility_()
    }

    class TestArchitectureContextWithRegistry {
        -TestRegistry _registry
        +TestArchitectureContextWithRegistry(TestRegistry registry)
        +override TUtility GetUtility_TUtility_()
    }

    class TestArchitectureWithRegistry {
        -TestRegistry _registry
        +IArchitectureContext Context
    }

    class TestArchitectureWithoutRegistry {
        +IArchitectureContext Context
    }

    IArchitectureLifecycleHook <|.. RegistryInitializationHookBase_TRegistry_TConfig_
    RegistryInitializationHookBase_TRegistry_TConfig_ ..> IArchitectureContext
    RegistryInitializationHookBase_TRegistry_TConfig_ ..> IArchitecture
    RegistryInitializationHookBase_TRegistry_TConfig_ ..> ArchitecturePhase
    RegistryInitializationHookBase_TRegistry_TConfig_ ..> IUtility

    RegistryInitializationHookBase_TRegistry_TConfig_ <|-- TestRegistryInitializationHook

    TestRegistry ..|> IUtility

    TestArchitectureWithRegistry ..|> IArchitecture
    TestArchitectureWithoutRegistry ..|> IArchitecture

    TestArchitectureContextWithRegistry --|> TestArchitectureContext
    TestArchitectureContext ..|> IArchitectureContext

    TestArchitectureWithRegistry o-- TestArchitectureContextWithRegistry
    TestArchitectureContextWithRegistry o-- TestRegistry
    TestArchitectureWithRegistry o-- TestRegistry
Loading

File-Level Changes

Change Details Files
Introduce IArchitectureContextProvider abstraction and concrete providers for global and scoped contexts, and wire them into the context-aware source generator.
  • Add IArchitectureContextProvider interface defining GetContext and generic TryGetContext methods to decouple context acquisition.
  • Implement GameContextProvider that uses GameContext.GetFirstArchitectureContext and GameContext.TryGet for default/global context resolution.
  • Implement ScopedContextProvider that wraps a specific IArchitectureContext instance and supports typed retrieval via pattern matching.
  • Update ContextAwareGenerator to hold a static IArchitectureContextProvider, lazily initialize it with GameContextProvider, and expose a static SetContextProvider method for overriding in tests or multi-architecture scenarios.
  • Adjust test snapshot in ContextAwareGeneratorSnapshotTests to reflect the new interface, provider implementations, and modified GameContext shape.
GFramework.Core.Abstractions/architecture/IArchitectureContextProvider.cs
GFramework.Core/architecture/GameContextProvider.cs
GFramework.Core/architecture/ScopedContextProvider.cs
GFramework.SourceGenerators/rule/ContextAwareGenerator.cs
GFramework.SourceGenerators.Tests/rule/ContextAwareGeneratorSnapshotTests.cs
GFramework.Core.Tests/architecture/ContextProviderTests.cs
Add a generic RegistryInitializationHookBase lifecycle hook to simplify registry-based configuration initialization and cover it with tests.
  • Create abstract RegistryInitializationHookBase<TRegistry,TConfig> implementing IArchitectureLifecycleHook, parameterized by registry type and config type.
  • Store a configs collection and target ArchitecturePhase, defaulting to AfterSystemInit, and in OnPhase retrieve the registry from architecture.Context and register each config.
  • Define abstract RegisterConfig for subclasses to implement concrete registration logic.
  • Add RegistryInitializationHookBaseTests with a concrete TestRegistryInitializationHook, TestRegistry utility, and architecture/context test doubles to validate behavior across phases, missing registries, empty configs, and repeated calls.
  • Make TestArchitectureContext.GetUtility virtual so it can be overridden in a derived test context used by the new tests.
GFramework.Core/architecture/RegistryInitializationHookBase.cs
GFramework.Core.Tests/architecture/RegistryInitializationHookBaseTests.cs
GFramework.Core.Tests/architecture/GameContextTests.cs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@deepsource-io

deepsource-io Bot commented Mar 1, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in f98c7f1...71d400d on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
C# Mar 2, 2026 4:36a.m. Review ↗
Secrets Mar 2, 2026 4:36a.m. Review ↗


T IArchitecture.RegisterSystem<T>(T system)
{
throw new NotImplementedException();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`NotImplementedException` being thrown


NotImplementedException is usually thrown to indicate that a particular feature or functionality is not yet implemented thus limiting the overall functionality of your application. This check lets you track all such instances across your codebase.


T IArchitecture.RegisterModel<T>(T model)
{
throw new NotImplementedException();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`NotImplementedException` being thrown


NotImplementedException is usually thrown to indicate that a particular feature or functionality is not yet implemented thus limiting the overall functionality of your application. This check lets you track all such instances across your codebase.


T IArchitecture.RegisterUtility<T>(T utility)
{
throw new NotImplementedException();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`NotImplementedException` being thrown


NotImplementedException is usually thrown to indicate that a particular feature or functionality is not yet implemented thus limiting the overall functionality of your application. This check lets you track all such instances across your codebase.


public void RegisterMediatorBehavior<TBehavior>() where TBehavior : class
{
throw new NotImplementedException();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`NotImplementedException` being thrown


NotImplementedException is usually thrown to indicate that a particular feature or functionality is not yet implemented thus limiting the overall functionality of your application. This check lets you track all such instances across your codebase.


public IArchitectureModule InstallModule(IArchitectureModule module)
{
throw new NotImplementedException();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`NotImplementedException` being thrown


NotImplementedException is usually thrown to indicate that a particular feature or functionality is not yet implemented thus limiting the overall functionality of your application. This check lets you track all such instances across your codebase.


public void RegisterModel<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, IModel
{
throw new NotImplementedException();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`NotImplementedException` being thrown


NotImplementedException is usually thrown to indicate that a particular feature or functionality is not yet implemented thus limiting the overall functionality of your application. This check lets you track all such instances across your codebase.


public void RegisterSystem<T>(Action<T>? onCreated = default(Action<T>?)) where T : class, ISystem
{
throw new NotImplementedException();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`NotImplementedException` being thrown


NotImplementedException is usually thrown to indicate that a particular feature or functionality is not yet implemented thus limiting the overall functionality of your application. This check lets you track all such instances across your codebase.


public Task InitializeAsync()
{
throw new NotImplementedException();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`NotImplementedException` being thrown


NotImplementedException is usually thrown to indicate that a particular feature or functionality is not yet implemented thus limiting the overall functionality of your application. This check lets you track all such instances across your codebase.


public ValueTask DestroyAsync()
{
throw new NotImplementedException();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`NotImplementedException` being thrown


NotImplementedException is usually thrown to indicate that a particular feature or functionality is not yet implemented thus limiting the overall functionality of your application. This check lets you track all such instances across your codebase.


public void Destroy()
{
throw new NotImplementedException();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`NotImplementedException` being thrown


NotImplementedException is usually thrown to indicate that a particular feature or functionality is not yet implemented thus limiting the overall functionality of your application. This check lets you track all such instances across your codebase.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - 我发现了 1 个问题,并留下了一些整体性反馈:

  • TestArchitectureContextWithRegistry 中,GetUtility<TUtility>() 的重写必须与基类方法签名保持一致(包括泛型约束和可空性),例如:public override TUtility? GetUtility<TUtility>() where TUtility : class, IUtility,否则这段代码将无法编译。
  • ContextAwareGenerator 中生成的 _contextProvider 字段是一个可变的静态单例,但没有任何重置/清理机制;建议提供一种方式来恢复默认的 provider(或将其设置为 null),以避免不同使用方和测试之间的状态泄漏。
给 AI 代理的提示
Please address the comments from this code review:

## Overall Comments
- In TestArchitectureContextWithRegistry, the override of GetUtility<TUtility>() must match the base method signature (including the generic constraint and nullability), e.g. `public override TUtility? GetUtility<TUtility>() where TUtility : class, IUtility`, otherwise this code will not compile.
- The generated `_contextProvider` field in ContextAwareGenerator is a static mutable singleton without any reset/clear mechanism; consider providing a way to restore the default provider (or set it to null) to avoid state leakage across consumers and tests.

## Individual Comments

### Comment 1
<location path="GFramework.Core.Tests/architecture/RegistryInitializationHookBaseTests.cs" line_range="271-278" />
<code_context>
+        _registry = registry;
+    }
+
+    public override TUtility GetUtility<TUtility>()
+    {
+        if (typeof(TUtility) == typeof(TestRegistry))
+        {
+            return _registry as TUtility;
+        }
+
+        return base.GetUtility<TUtility>();
+    }
+}
</code_context>
<issue_to_address>
**issue (bug_risk):** Override signature should match base method's nullability and generic constraints.

`TestArchitectureContext.GetUtility<TUtility>()` is now `public virtual TUtility? GetUtility<TUtility>() where TUtility : class, IUtility`, but this override omits the `where TUtility : class, IUtility` constraint and uses a non-nullable return type. In C#, overrides must match the base signature exactly (including generic constraints and nullability), otherwise this will not compile. Update this method to:

```csharp
public override TUtility? GetUtility<TUtility>() where TUtility : class, IUtility
{
    if (typeof(TUtility) == typeof(TestRegistry))
    {
        return _registry as TUtility;
    }

    return base.GetUtility<TUtility>();
}
```

This also correctly models that `_registry as TUtility` may be null.
</issue_to_address>

Sourcery 对开源是免费的——如果你觉得这些评论有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的代码审查。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • In TestArchitectureContextWithRegistry, the override of GetUtility() must match the base method signature (including the generic constraint and nullability), e.g. public override TUtility? GetUtility<TUtility>() where TUtility : class, IUtility, otherwise this code will not compile.
  • The generated _contextProvider field in ContextAwareGenerator is a static mutable singleton without any reset/clear mechanism; consider providing a way to restore the default provider (or set it to null) to avoid state leakage across consumers and tests.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In TestArchitectureContextWithRegistry, the override of GetUtility<TUtility>() must match the base method signature (including the generic constraint and nullability), e.g. `public override TUtility? GetUtility<TUtility>() where TUtility : class, IUtility`, otherwise this code will not compile.
- The generated `_contextProvider` field in ContextAwareGenerator is a static mutable singleton without any reset/clear mechanism; consider providing a way to restore the default provider (or set it to null) to avoid state leakage across consumers and tests.

## Individual Comments

### Comment 1
<location path="GFramework.Core.Tests/architecture/RegistryInitializationHookBaseTests.cs" line_range="271-278" />
<code_context>
+        _registry = registry;
+    }
+
+    public override TUtility GetUtility<TUtility>()
+    {
+        if (typeof(TUtility) == typeof(TestRegistry))
+        {
+            return _registry as TUtility;
+        }
+
+        return base.GetUtility<TUtility>();
+    }
+}
</code_context>
<issue_to_address>
**issue (bug_risk):** Override signature should match base method's nullability and generic constraints.

`TestArchitectureContext.GetUtility<TUtility>()` is now `public virtual TUtility? GetUtility<TUtility>() where TUtility : class, IUtility`, but this override omits the `where TUtility : class, IUtility` constraint and uses a non-nullable return type. In C#, overrides must match the base signature exactly (including generic constraints and nullability), otherwise this will not compile. Update this method to:

```csharp
public override TUtility? GetUtility<TUtility>() where TUtility : class, IUtility
{
    if (typeof(TUtility) == typeof(TestRegistry))
    {
        return _registry as TUtility;
    }

    return base.GetUtility<TUtility>();
}
```

This also correctly models that `_registry as TUtility` may be null.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +271 to +278
public override TUtility GetUtility<TUtility>()
{
if (typeof(TUtility) == typeof(TestRegistry))
{
return _registry as TUtility;
}

return base.GetUtility<TUtility>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): 重写方法的签名应与基类方法的可空性和泛型约束保持一致。

TestArchitectureContext.GetUtility<TUtility>() 现在是 public virtual TUtility? GetUtility<TUtility>() where TUtility : class, IUtility,但当前这个重写方法省略了 where TUtility : class, IUtility 约束,并且返回类型是非可空的。在 C# 中,重写方法必须与基类方法签名完全匹配(包括泛型约束和可空性),否则无法通过编译。请将该方法更新为:

public override TUtility? GetUtility<TUtility>() where TUtility : class, IUtility
{
    if (typeof(TUtility) == typeof(TestRegistry))
    {
        return _registry as TUtility;
    }

    return base.GetUtility<TUtility>();
}

这也能更准确地表示 _registry as TUtility 可能为 null。

Original comment in English

issue (bug_risk): Override signature should match base method's nullability and generic constraints.

TestArchitectureContext.GetUtility<TUtility>() is now public virtual TUtility? GetUtility<TUtility>() where TUtility : class, IUtility, but this override omits the where TUtility : class, IUtility constraint and uses a non-nullable return type. In C#, overrides must match the base signature exactly (including generic constraints and nullability), otherwise this will not compile. Update this method to:

public override TUtility? GetUtility<TUtility>() where TUtility : class, IUtility
{
    if (typeof(TUtility) == typeof(TestRegistry))
    {
        return _registry as TUtility;
    }

    return base.GetUtility<TUtility>();
}

This also correctly models that _registry as TUtility may be null.

GeWuYou added 2 commits March 2, 2026 12:34
- 添加 ResetContextProvider 方法用于重置上下文提供者为默认值
- 为方法添加 XML 文档注释说明用途
- 实现测试清理相关的上下文管理功能
- 排除 **/*.Tests.cs 模式
- 排除 **/*Test.cs 模式
- 排除 **/tests/** 目录
- 排除 **/*Tests.cs 模式
- 排除 **/Tests/** 目录
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