You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
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
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
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.
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.
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!
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
<locationpath="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:
```csharppublicoverrideTUtility?GetUtility<TUtility>() whereTUtility: class, IUtility
{
if (typeof(TUtility) == typeof(TestRegistry))
{
return_registryasTUtility;
}
return base.GetUtility<TUtility>();
}
```
This also correctly models that `_registry as TUtility` may be null.
</issue_to_address>
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的代码审查。
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
<locationpath="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:
```csharppublicoverrideTUtility?GetUtility<TUtility>() whereTUtility: class, IUtility
{
if (typeof(TUtility) == typeof(TestRegistry))
{
return_registryasTUtility;
}
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 ✨
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:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary by Sourcery
引入用于提供架构上下文的抽象,并将其集成到具备上下文感知的代码生成中,同时新增用于注册表初始化的基础设施及相应测试。
New Features:
IArchitectureContextProvider接口,以及默认实现GameContextProvider和ScopedContextProvider,用于获取架构上下文。RegistryInitializationHookBase,以便在特定架构生命周期阶段,将配置项注册到各类工具中,从而简化注册流程。Enhancements:
IArchitectureContextProvider来解析Context属性。TestArchitectureContext.GetUtility,以在新测试中支持自定义测试上下文。Tests:
RegistryInitializationHookBase添加单元测试,覆盖阶段行为、缺失注册表、空配置以及重复调用等情况。GameContextProvider和ScopedContextProvider添加单元测试,以验证上下文获取和类型安全查找行为。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:
Enhancements:
Tests: