Skip to content

Feat/add priority service resolution#80

Merged
GeWuYou merged 3 commits into
mainfrom
feat/add-priority-service-resolution
Mar 5, 2026
Merged

Feat/add priority service resolution#80
GeWuYou merged 3 commits into
mainfrom
feat/add-priority-service-resolution

Conversation

@GeWuYou
Copy link
Copy Markdown
Owner

@GeWuYou GeWuYou commented Mar 5, 2026

Summary by Sourcery

添加一个支持优先级的抽象和源代码生成器,并在 IoC 容器和架构上下文中集成基于优先级的解析机制。

New Features:

  • 引入 IPrioritized 接口、PriorityGroup 常量以及 PriorityAttribute,以声明式方式为组件分配执行优先级。
  • 为 IoC 容器、架构上下文以及面向服务、系统、模型和工具的上下文感知扩展添加基于优先级的检索 API。
  • 实现 PriorityGenerator 源代码生成器和 PriorityUsageAnalyzer,用于自动实现 IPrioritized 并建议使用支持优先级的解析方法。

Enhancements:

  • PauseToken 补充更丰富的 XML 文档,以提高使用说明的清晰度。
  • 在分析器发行说明中登记新的与优先级相关的分析器诊断信息。

Tests:

  • 为 IoC 容器和架构上下文中基于优先级的服务排序添加全面的单元测试和集成测试。
  • PriorityGenerator 源代码生成器添加快照测试,用于验证针对各种类形式生成的代码。
Original summary in English

Summary by Sourcery

Add a priority-aware abstraction and source generator, and integrate priority-based resolution across the IoC container and architecture context.

New Features:

  • Introduce IPrioritized interface, PriorityGroup constants, and PriorityAttribute to declaratively assign execution priority to components.
  • Add priority-based retrieval APIs to the IoC container, architecture context, and context-aware extensions for services, systems, models, and utilities.
  • Implement a PriorityGenerator source generator and PriorityUsageAnalyzer to auto-implement IPrioritized and suggest using priority-aware resolution methods.

Enhancements:

  • Extend PauseToken with richer XML documentation for clarity of usage.
  • Register new priority-related analyzer diagnostics in the analyzer release notes.

Tests:

  • Add comprehensive unit and integration tests for priority-based service ordering in the IoC container and architecture context.
  • Add snapshot tests for the PriorityGenerator source generator to validate generated code for various class forms.

GeWuYou added 2 commits March 5, 2026 21:29
- 在 ArchitectureContext 中添加 GetServicesByPriority、GetSystemsByPriority、
  GetModelsByPriority 和 GetUtilitiesByPriority 方法
- 在 ContextAwareServiceExtensions 中添加对应的扩展方法支持按优先级获取实例
- 在 MicrosoftDiContainer 中实现 GetAllByPriority 方法和 SortByPriority 排序逻辑
- 在抽象层定义 IPrioritized 接口用于标记可排序的服务组件
- 为 PauseToken 添加完整的相等性比较和字符串转换方法
- 添加全面的单元测试验证优先级排序功能的正确性
- 新增 PriorityGenerator 源生成器,自动生成 IPrioritized 接口实现
- 添加 PriorityAttribute 特性,用于标记类的优先级值
- 实现 PriorityUsageAnalyzer 分析器,检测优先级使用建议
- 添加预定义的 PriorityGroup 常量,提供标准优先级分组
- 在 AnalyzerReleases.Unshipped.md 中注册新的诊断规则
- 更新项目依赖,升级 Meziantou.Analyzer 和 Polyfill 版本
- 为测试项目添加源生成器项目引用
- 添加 PriorityGenerator 的快照测试用例
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Mar 5, 2026

Reviewer's Guide

在整个 IoC 容器和架构上下文中新增基于优先级的解析机制,引入 IPrioritized 和 PriorityAttribute,并通过源生成器/分析器自动实现和校验优先级用法,同时提供围绕优先级排序与生成器行为的完整单元测试和快照测试。

通过具备上下文感知扩展方法解析带优先级服务的时序图

sequenceDiagram
    actor Client
    participant ContextAware as IContextAware
    participant Extensions as ContextAwareServiceExtensions
    participant ArchCtx as ArchitectureContext
    participant Container as MicrosoftDiContainer

    Client->>ContextAware: GetServicesByPriority~IMyService~() extension
    activate ContextAware
    ContextAware->>Extensions: GetServicesByPriority~IMyService~(contextAware)
    activate Extensions
    Extensions->>ContextAware: GetContext()
    ContextAware-->>Extensions: IArchitectureContext
    Extensions->>ArchCtx: GetServicesByPriority~IMyService~()
    activate ArchCtx
    ArchCtx->>Container: GetAllByPriority~IMyService~()
    activate Container
    Container->>Container: GetAll~IMyService~()
    Container->>Container: SortByPriority~IMyService~(services)
    Container-->>ArchCtx: IReadOnlyList~IMyService~
    deactivate Container
    ArchCtx-->>Extensions: IReadOnlyList~IMyService~
    deactivate ArchCtx
    Extensions-->>Client: IReadOnlyList~IMyService~
    deactivate Extensions
    deactivate ContextAware
Loading

优先级抽象、特性、生成器和分析器的类图

classDiagram
    direction TB

    class IPrioritized {
        <<interface>>
        +int Priority
    }

    class PriorityGroup {
        <<static>>
        +const int Critical
        +const int High
        +const int Normal
        +const int Low
        +const int Deferred
    }

    class PriorityAttribute {
        +PriorityAttribute(int value)
        +int Value
    }

    class PriorityDiagnostic {
        <<static>>
        +DiagnosticDescriptor OnlyApplyToClass
        +DiagnosticDescriptor AlreadyImplemented
        +DiagnosticDescriptor MustBePartial
        +DiagnosticDescriptor InvalidValue
    }

    class PriorityGenerator {
        <<generator>>
        -string AttributeMetadataName
        -string AttributeShortNameWithoutSuffix
        +bool ValidateSymbol(SourceProductionContext context, Compilation compilation, ClassDeclarationSyntax syntax, INamedTypeSymbol symbol, AttributeData attr)
        +string Generate(SourceProductionContext context, Compilation compilation, INamedTypeSymbol symbol, AttributeData attr)
        +string GetHintName(INamedTypeSymbol symbol)
    }

    class PriorityUsageAnalyzer {
        <<analyzer>>
        -const string DiagnosticId
        -static DiagnosticDescriptor Rule
        +Initialize(AnalysisContext context)
    }

    class MetadataAttributeClassGeneratorBase {
        <<abstract>>
        +Execute()
    }

    class DiagnosticDescriptor
    class SourceProductionContext
    class Compilation
    class ClassDeclarationSyntax
    class INamedTypeSymbol
    class AttributeData
    class AnalysisContext

    PriorityAttribute ..|> Attribute
    PriorityGenerator ..|> MetadataAttributeClassGeneratorBase
    PriorityUsageAnalyzer ..|> DiagnosticAnalyzer

    PriorityGenerator ..> PriorityAttribute : reads
    PriorityGenerator ..> IPrioritized : generates implementation
    PriorityGenerator ..> PriorityDiagnostic : reports

    PriorityUsageAnalyzer ..> IPrioritized : checks implementations
    PriorityUsageAnalyzer ..> PriorityDiagnostic : uses rule ids

    IPrioritized <.. PriorityGroup : uses constants

    class Attribute
    class DiagnosticAnalyzer
Loading

IoC 与架构优先级解析 API 的类图

classDiagram
    direction TB

    class IIocContainer {
        <<interface>>
        +IReadOnlyList~T~ GetAll~T~()
        +IReadOnlyList~T~ GetAllSorted~T~(Comparison~T~ comparison)
        +IReadOnlyList~T~ GetAllByPriority~T~()
        +IReadOnlyList~object~ GetAllByPriority(Type type)
    }

    class MicrosoftDiContainer {
        +IReadOnlyList~T~ GetAll~T~()
        +IReadOnlyList~T~ GetAllSorted~T~(Comparison~T~ comparison)
        +IReadOnlyList~T~ GetAllByPriority~T~()
        +IReadOnlyList~object~ GetAllByPriority(Type type)
        -IReadOnlyList~T~ SortByPriority~T~(IReadOnlyList~T~ services)
    }

    class IArchitectureContext {
        <<interface>>
        +IReadOnlyList~TService~ GetServices~TService~()
        +IReadOnlyList~TSystem~ GetSystems~TSystem~()
        +IReadOnlyList~TModel~ GetModels~TModel~()
        +IReadOnlyList~TUtility~ GetUtilities~TUtility~()
        +IReadOnlyList~TService~ GetServicesByPriority~TService~()
        +IReadOnlyList~TSystem~ GetSystemsByPriority~TSystem~()
        +IReadOnlyList~TModel~ GetModelsByPriority~TModel~()
        +IReadOnlyList~TUtility~ GetUtilitiesByPriority~TUtility~()
    }

    class ArchitectureContext {
        -IIocContainer _container
        +IReadOnlyList~TService~ GetServices~TService~()
        +IReadOnlyList~TSystem~ GetSystems~TSystem~()
        +IReadOnlyList~TModel~ GetModels~TModel~()
        +IReadOnlyList~TUtility~ GetUtilities~TUtility~()
        +IReadOnlyList~TService~ GetServicesByPriority~TService~()
        +IReadOnlyList~TSystem~ GetSystemsByPriority~TSystem~()
        +IReadOnlyList~TModel~ GetModelsByPriority~TModel~()
        +IReadOnlyList~TUtility~ GetUtilitiesByPriority~TUtility~()
    }

    class IContextAware {
        <<interface>>
        +IArchitectureContext GetContext()
    }

    class ContextAwareServiceExtensions {
        <<static>>
        +IReadOnlyList~TService~ GetServicesByPriority~TService~(IContextAware contextAware)
        +IReadOnlyList~TSystem~ GetSystemsByPriority~TSystem~(IContextAware contextAware)
        +IReadOnlyList~TModel~ GetModelsByPriority~TModel~(IContextAware contextAware)
        +IReadOnlyList~TUtility~ GetUtilitiesByPriority~TUtility~(IContextAware contextAware)
    }

    class IPrioritized {
        <<interface>>
        +int Priority
    }

    MicrosoftDiContainer ..|> IIocContainer
    ArchitectureContext ..|> IArchitectureContext

    ArchitectureContext o--> IIocContainer : uses
    ContextAwareServiceExtensions ..> IContextAware : extension
    ContextAwareServiceExtensions ..> IArchitectureContext : calls

    IIocContainer ..> IPrioritized : sort by Priority
    ArchitectureContext ..> IIocContainer : GetAllByPriority

    class Comparison~T~
    class Type
    class IReadOnlyList~T~
Loading

PriorityUsageAnalyzer 决策逻辑的流程图

flowchart TD
    A["Start: InvocationOperation"] --> B{"TargetMethod.Name == GetAll?"}
    B -- No --> Z["Exit"]
    B -- Yes --> C{"Is generic and has 1 type argument?"}
    C -- No --> Z
    C -- Yes --> D{"Containing type is IIocContainer or IArchitectureContext?"}
    D -- No --> Z
    D -- Yes --> E["Get type argument T"]
    E --> F{"T implements IPrioritized?"}
    F -- No --> Z
    F -- Yes --> G["Report diagnostic: suggest GetAllByPriority<T>()"]
    G --> Z
    Z["End"]
Loading

File-Level Changes

Change Details Files
在 IoC 和架构层引入 IPrioritized 抽象、预定义优先级分组以及基于优先级的检索 API。
  • 新增 IPrioritized 接口和 PriorityGroup 常量,用于表示并标准化优先级语义(数值越小优先级越高)。
  • 扩展 IIocContainer 和 MicrosoftDiContainer,增加 GetAllByPriority 的泛型及基于 Type 的重载,并添加内部 SortByPriority 帮助方法,使用稳定的升序排序,对非 IPrioritized 实例使用默认优先级 0。
  • 在 IArchitectureContext、ArchitectureContext 和 ContextAwareServiceExtensions 上暴露面向服务、系统、模型和工具的优先级感知检索方法,并在 ArchitectureServicesTests/GameContextTests 中通过测试替身接线到容器的优先级检索。
GFramework.Core.Abstractions/bases/IPrioritized.cs
GFramework.Core.Abstractions/bases/PriorityGroup.cs
GFramework.Core.Abstractions/ioc/IIocContainer.cs
GFramework.Core/ioc/MicrosoftDiContainer.cs
GFramework.Core/architecture/ArchitectureContext.cs
GFramework.Core/extensions/ContextAwareServiceExtensions.cs
GFramework.Core.Abstractions/architecture/IArchitectureContext.cs
GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs
GFramework.Core.Tests/architecture/GameContextTests.cs
添加源生成器、特性、诊断和分析器支持,以提供编译期优先级实现和使用指引。
  • 在源生成器抽象中引入 PriorityAttribute,用于在类上声明式指定优先级,同时避免手动实现 IPrioritized。
  • 实现 PriorityGenerator 以检测带有 [Priority] 标注的 partial 类,校验用法(仅限类、必须为 partial、未已实现 IPrioritized、且 int 参数合法),并生成带有 Priority 属性的 IPrioritized 实现;添加 PriorityDiagnostic 帮助类并注册新的分析器规则 ID。
  • 创建 PriorityUsageAnalyzer,当通过 IIocContainer/IArchitectureContext 解析 IPrioritized 类型时,推荐使用 GetAllByPriority 而不是 GetAll,并在 AnalyzerReleases.Unshipped.md 中注册与优先级相关的诊断。
GFramework.SourceGenerators.Abstractions/bases/PriorityAttribute.cs
GFramework.SourceGenerators/bases/PriorityGenerator.cs
GFramework.SourceGenerators/diagnostics/PriorityDiagnostic.cs
GFramework.SourceGenerators/analyzers/PriorityUsageAnalyzer.cs
GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md
添加验证优先级排序语义和生成器行为的单元测试与快照测试,并对 PauseToken 文档做了小幅改进。
  • 为 MicrosoftDiContainer 新增围绕 GetAllByPriority 的测试,包括排序顺序、非 IPrioritized 的默认优先级、相同优先级时的稳定性、空/单元素列表、混合有/无优先级的情况以及基于 Type 的重载。
  • 新增 PriorityServiceTests,用于验证在真实容器配置下,对于系统、模型和工具的优先级排序集成行为,包含混合优先级与非优先级系统。
  • 新增 PriorityGeneratorSnapshotTests,覆盖 [Priority] 的基础、负数、分组、泛型以及嵌套类场景,并略微提升 PauseToken XML 文档的清晰度。
GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs
GFramework.Core.Tests/architecture/PriorityServiceTests.cs
GFramework.SourceGenerators.Tests/bases/PriorityGeneratorSnapshotTests.cs
GFramework.Core.Abstractions/pause/PauseToken.cs

Tips and commands

Interacting with 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 摘要。你也可以评论 @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 来触发新的评审!

Customizing Your Experience

访问你的 dashboard 以:

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

Getting Help

Original review guide in English

Reviewer's Guide

Adds a priority-based resolution mechanism across the IoC container and architecture context, introduces IPrioritized and PriorityAttribute plus source generator/analyzers to auto-implement and validate priority usage, and supplies comprehensive unit and snapshot tests around priority ordering and generator behavior.

Sequence diagram for resolving prioritized services via context-aware extensions

sequenceDiagram
    actor Client
    participant ContextAware as IContextAware
    participant Extensions as ContextAwareServiceExtensions
    participant ArchCtx as ArchitectureContext
    participant Container as MicrosoftDiContainer

    Client->>ContextAware: GetServicesByPriority~IMyService~() extension
    activate ContextAware
    ContextAware->>Extensions: GetServicesByPriority~IMyService~(contextAware)
    activate Extensions
    Extensions->>ContextAware: GetContext()
    ContextAware-->>Extensions: IArchitectureContext
    Extensions->>ArchCtx: GetServicesByPriority~IMyService~()
    activate ArchCtx
    ArchCtx->>Container: GetAllByPriority~IMyService~()
    activate Container
    Container->>Container: GetAll~IMyService~()
    Container->>Container: SortByPriority~IMyService~(services)
    Container-->>ArchCtx: IReadOnlyList~IMyService~
    deactivate Container
    ArchCtx-->>Extensions: IReadOnlyList~IMyService~
    deactivate ArchCtx
    Extensions-->>Client: IReadOnlyList~IMyService~
    deactivate Extensions
    deactivate ContextAware
Loading

Class diagram for priority abstractions, attribute, generator, and analyzer

classDiagram
    direction TB

    class IPrioritized {
        <<interface>>
        +int Priority
    }

    class PriorityGroup {
        <<static>>
        +const int Critical
        +const int High
        +const int Normal
        +const int Low
        +const int Deferred
    }

    class PriorityAttribute {
        +PriorityAttribute(int value)
        +int Value
    }

    class PriorityDiagnostic {
        <<static>>
        +DiagnosticDescriptor OnlyApplyToClass
        +DiagnosticDescriptor AlreadyImplemented
        +DiagnosticDescriptor MustBePartial
        +DiagnosticDescriptor InvalidValue
    }

    class PriorityGenerator {
        <<generator>>
        -string AttributeMetadataName
        -string AttributeShortNameWithoutSuffix
        +bool ValidateSymbol(SourceProductionContext context, Compilation compilation, ClassDeclarationSyntax syntax, INamedTypeSymbol symbol, AttributeData attr)
        +string Generate(SourceProductionContext context, Compilation compilation, INamedTypeSymbol symbol, AttributeData attr)
        +string GetHintName(INamedTypeSymbol symbol)
    }

    class PriorityUsageAnalyzer {
        <<analyzer>>
        -const string DiagnosticId
        -static DiagnosticDescriptor Rule
        +Initialize(AnalysisContext context)
    }

    class MetadataAttributeClassGeneratorBase {
        <<abstract>>
        +Execute()
    }

    class DiagnosticDescriptor
    class SourceProductionContext
    class Compilation
    class ClassDeclarationSyntax
    class INamedTypeSymbol
    class AttributeData
    class AnalysisContext

    PriorityAttribute ..|> Attribute
    PriorityGenerator ..|> MetadataAttributeClassGeneratorBase
    PriorityUsageAnalyzer ..|> DiagnosticAnalyzer

    PriorityGenerator ..> PriorityAttribute : reads
    PriorityGenerator ..> IPrioritized : generates implementation
    PriorityGenerator ..> PriorityDiagnostic : reports

    PriorityUsageAnalyzer ..> IPrioritized : checks implementations
    PriorityUsageAnalyzer ..> PriorityDiagnostic : uses rule ids

    IPrioritized <.. PriorityGroup : uses constants

    class Attribute
    class DiagnosticAnalyzer
Loading

Class diagram for IoC and architecture priority resolution APIs

classDiagram
    direction TB

    class IIocContainer {
        <<interface>>
        +IReadOnlyList~T~ GetAll~T~()
        +IReadOnlyList~T~ GetAllSorted~T~(Comparison~T~ comparison)
        +IReadOnlyList~T~ GetAllByPriority~T~()
        +IReadOnlyList~object~ GetAllByPriority(Type type)
    }

    class MicrosoftDiContainer {
        +IReadOnlyList~T~ GetAll~T~()
        +IReadOnlyList~T~ GetAllSorted~T~(Comparison~T~ comparison)
        +IReadOnlyList~T~ GetAllByPriority~T~()
        +IReadOnlyList~object~ GetAllByPriority(Type type)
        -IReadOnlyList~T~ SortByPriority~T~(IReadOnlyList~T~ services)
    }

    class IArchitectureContext {
        <<interface>>
        +IReadOnlyList~TService~ GetServices~TService~()
        +IReadOnlyList~TSystem~ GetSystems~TSystem~()
        +IReadOnlyList~TModel~ GetModels~TModel~()
        +IReadOnlyList~TUtility~ GetUtilities~TUtility~()
        +IReadOnlyList~TService~ GetServicesByPriority~TService~()
        +IReadOnlyList~TSystem~ GetSystemsByPriority~TSystem~()
        +IReadOnlyList~TModel~ GetModelsByPriority~TModel~()
        +IReadOnlyList~TUtility~ GetUtilitiesByPriority~TUtility~()
    }

    class ArchitectureContext {
        -IIocContainer _container
        +IReadOnlyList~TService~ GetServices~TService~()
        +IReadOnlyList~TSystem~ GetSystems~TSystem~()
        +IReadOnlyList~TModel~ GetModels~TModel~()
        +IReadOnlyList~TUtility~ GetUtilities~TUtility~()
        +IReadOnlyList~TService~ GetServicesByPriority~TService~()
        +IReadOnlyList~TSystem~ GetSystemsByPriority~TSystem~()
        +IReadOnlyList~TModel~ GetModelsByPriority~TModel~()
        +IReadOnlyList~TUtility~ GetUtilitiesByPriority~TUtility~()
    }

    class IContextAware {
        <<interface>>
        +IArchitectureContext GetContext()
    }

    class ContextAwareServiceExtensions {
        <<static>>
        +IReadOnlyList~TService~ GetServicesByPriority~TService~(IContextAware contextAware)
        +IReadOnlyList~TSystem~ GetSystemsByPriority~TSystem~(IContextAware contextAware)
        +IReadOnlyList~TModel~ GetModelsByPriority~TModel~(IContextAware contextAware)
        +IReadOnlyList~TUtility~ GetUtilitiesByPriority~TUtility~(IContextAware contextAware)
    }

    class IPrioritized {
        <<interface>>
        +int Priority
    }

    MicrosoftDiContainer ..|> IIocContainer
    ArchitectureContext ..|> IArchitectureContext

    ArchitectureContext o--> IIocContainer : uses
    ContextAwareServiceExtensions ..> IContextAware : extension
    ContextAwareServiceExtensions ..> IArchitectureContext : calls

    IIocContainer ..> IPrioritized : sort by Priority
    ArchitectureContext ..> IIocContainer : GetAllByPriority

    class Comparison~T~
    class Type
    class IReadOnlyList~T~
Loading

Flow diagram for PriorityUsageAnalyzer decision logic

flowchart TD
    A["Start: InvocationOperation"] --> B{"TargetMethod.Name == GetAll?"}
    B -- No --> Z["Exit"]
    B -- Yes --> C{"Is generic and has 1 type argument?"}
    C -- No --> Z
    C -- Yes --> D{"Containing type is IIocContainer or IArchitectureContext?"}
    D -- No --> Z
    D -- Yes --> E["Get type argument T"]
    E --> F{"T implements IPrioritized?"}
    F -- No --> Z
    F -- Yes --> G["Report diagnostic: suggest GetAllByPriority<T>()"]
    G --> Z
    Z["End"]
Loading

File-Level Changes

Change Details Files
Introduce IPrioritized abstraction, predefined priority groups, and priority-based retrieval APIs across IoC and architecture layers.
  • Add IPrioritized interface and PriorityGroup constants to represent and standardize priority semantics (smaller value = higher priority).
  • Extend IIocContainer and MicrosoftDiContainer with GetAllByPriority generic and Type-based overloads plus an internal SortByPriority helper using stable ascending sort and default priority 0 for non-IPrioritized instances.
  • Expose priority-aware retrieval methods on IArchitectureContext, ArchitectureContext, and ContextAwareServiceExtensions for services, systems, models, and utilities, and wire test doubles in ArchitectureServicesTests/GameContextTests to delegate to container priority retrieval.
GFramework.Core.Abstractions/bases/IPrioritized.cs
GFramework.Core.Abstractions/bases/PriorityGroup.cs
GFramework.Core.Abstractions/ioc/IIocContainer.cs
GFramework.Core/ioc/MicrosoftDiContainer.cs
GFramework.Core/architecture/ArchitectureContext.cs
GFramework.Core/extensions/ContextAwareServiceExtensions.cs
GFramework.Core.Abstractions/architecture/IArchitectureContext.cs
GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs
GFramework.Core.Tests/architecture/GameContextTests.cs
Add source generator, attribute, diagnostics, and analyzer support for compile-time priority implementation and usage guidance.
  • Introduce PriorityAttribute in source-generators abstractions to declaratively specify priority on classes while avoiding manual IPrioritized implementation.
  • Implement PriorityGenerator to detect [Priority]-annotated partial classes, validate usage (class-only, partial, not already implementing IPrioritized, valid int argument), and emit IPrioritized implementation with a Priority property; add PriorityDiagnostic helpers and register new analyzer rule IDs.
  • Create PriorityUsageAnalyzer to recommend GetAllByPriority instead of GetAll when resolving IPrioritized types via IIocContainer/IArchitectureContext, and register Priority-related diagnostics in AnalyzerReleases.Unshipped.md.
GFramework.SourceGenerators.Abstractions/bases/PriorityAttribute.cs
GFramework.SourceGenerators/bases/PriorityGenerator.cs
GFramework.SourceGenerators/diagnostics/PriorityDiagnostic.cs
GFramework.SourceGenerators/analyzers/PriorityUsageAnalyzer.cs
GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md
Add unit and snapshot tests validating priority sorting semantics and generator behavior, plus minor PauseToken doc improvements.
  • Add MicrosoftDiContainer tests around GetAllByPriority including ordering, default priority for non-IPrioritized, stability for equal priorities, empty/single lists, mixed prioritized/non-prioritized, and Type-based overload.
  • Add PriorityServiceTests to verify integration of priority sorting for systems, models, and utilities in a real container setup with mixed prioritized and non-prioritized systems.
  • Add PriorityGeneratorSnapshotTests to cover basic, negative, grouped, generic, and nested-class [Priority] scenarios, and slightly enhance PauseToken XML documentation for clarity.
GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs
GFramework.Core.Tests/architecture/PriorityServiceTests.cs
GFramework.SourceGenerators.Tests/bases/PriorityGeneratorSnapshotTests.cs
GFramework.Core.Abstractions/pause/PauseToken.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
Copy link
Copy Markdown

deepsource-io Bot commented Mar 5, 2026

DeepSource Code Review

We reviewed changes in 71b5831...a6a1c9f 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 5, 2026 2:47p.m. Review ↗
Secrets Mar 5, 2026 2:47p.m. Review ↗

Comment thread GFramework.SourceGenerators/bases/PriorityGenerator.cs Outdated
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - 我发现了 3 个问题,并留下了一些总体反馈:

  • PriorityUsageAnalyzer 使用了硬编码的诊断 ID GF_Priority_Usage_001,而 AnalyzerReleases.Unshipped.md 注册的是 GF_Priority_001GF_Priority_004;建议对齐诊断 ID,并使用已有的 PriorityDiagnostic 描述符,这样分析器的诊断才能被发现,并与发布元数据保持一致。
  • PriorityGenerator.GetHintName 中,仅使用 symbol.Name 作为生成文件名,在存在嵌套类型或不同命名空间下同名类型时会导致冲突;建议在提示名称中包含命名空间和嵌套信息(例如使用元数据名称),以保证唯一性。
  • 当前优先级排序逻辑只实现于 MicrosoftDiContainer.SortByPriority 中;由于现在相同语义也通过 ArchitectureContext 和多个扩展方法暴露出来,建议将该排序行为集中到一个共享的辅助方法中,以避免将来规则变更时出现细微差异。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `PriorityUsageAnalyzer` uses the hard-coded diagnostic ID `GF_Priority_Usage_001`, whereas `AnalyzerReleases.Unshipped.md` registers `GF_Priority_001``GF_Priority_004`; consider aligning the ID and using the existing `PriorityDiagnostic` descriptors so the analyzer’s diagnostics are discoverable and consistent with the release metadata.
- In `PriorityGenerator.GetHintName`, using only `symbol.Name` for the generated file name can cause collisions for nested types or types with the same name in different namespaces; consider including namespace and nesting (e.g., metadata name) in the hint name to ensure uniqueness.
- The priority-sorting logic is currently implemented only inside `MicrosoftDiContainer.SortByPriority`; since the same semantics are now exposed via `ArchitectureContext` and multiple extension methods, it may be worthwhile to centralize this sorting behavior in a shared helper to avoid subtle divergence if the rules change later.

## Individual Comments

### Comment 1
<location path="GFramework.Core/ioc/MicrosoftDiContainer.cs" line_range="638-595" />
<code_context>
+        var list = services.ToList();
+
+        // 稳定排序:相同优先级保持注册顺序
+        list.Sort((a, b) =>
+        {
+            var priorityA = a is IPrioritized pa ? pa.Priority : 0;
+            var priorityB = b is IPrioritized pb ? pb.Priority : 0;
+            return priorityA.CompareTo(priorityB); // 升序
+        });
+
+        return list;
+    }
+
</code_context>
<issue_to_address>
**issue (bug_risk):** The use of List.Sort here contradicts the "stable sort" guarantee in the comment and tests.

Because List<T>.Sort is not stable, items with the same Priority may not preserve registration order, causing flaky behavior that contradicts the documented contract. To ensure stability, use an approach that includes the original index in the sort key (e.g., sort by (priority, index)) or use OrderBy with an index selector instead of List.Sort.
</issue_to_address>

### Comment 2
<location path="GFramework.SourceGenerators/bases/PriorityGenerator.cs" line_range="115-122" />
<code_context>
+            ? $"<{string.Join(", ", symbol.TypeParameters.Select(tp => tp.Name))}>"
+            : string.Empty;
+
+        sb.AppendLine(
+            $"partial class {symbol.Name}{typeParameters} : global::GFramework.Core.Abstractions.bases.IPrioritized");
+        sb.AppendLine("{");
+        sb.AppendLine("    /// <summary>");
+        sb.AppendLine($"    /// 获取优先级值: {priorityValue}");
+        sb.AppendLine("    /// </summary>");
+        sb.AppendLine($"    public int Priority => {priorityValue};");
+        sb.AppendLine("}");
+
+        return sb.ToString().TrimEnd();
</code_context>
<issue_to_address>
**issue:** Generated partial class does not account for nesting, which will break for nested types.

For nested classes, `symbol.Name` only gives the innermost type name, so the generator emits a top-level partial in the namespace instead of matching the original nesting (e.g., `OuterClass.NestedSystem`). This will fail to compile for nested (and some generic/nested) types. Consider emitting the full containing type hierarchy (e.g., wrapping in partials for containing types or constructing the full nested type name) so the generated partial structurally matches the original declaration.
</issue_to_address>

### Comment 3
<location path="GFramework.Core/ioc/MicrosoftDiContainer.cs" line_range="613" />
<code_context>
+
+    /// <summary>
+    /// 获取指定类型的所有实例,并按优先级排序
+    /// 实现 IPrioritized 接口的服务将按值越小优先级越高)
+    /// 未实现 IPrioritized 的服务将使用默认优先级 0
+    /// </summary>
</code_context>
<issue_to_address>
**nitpick (typo):** Minor typo in XML documentation for GetAllByPriority(Type).

The Chinese summary line is missing an opening parenthesis before “值”, e.g. it should read “按优先级排序(数值越小优先级越高)” to be clear and grammatically correct.
</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.
Original comment in English

Hey - I've found 3 issues, and left some high level feedback:

  • The PriorityUsageAnalyzer uses the hard-coded diagnostic ID GF_Priority_Usage_001, whereas AnalyzerReleases.Unshipped.md registers GF_Priority_001GF_Priority_004; consider aligning the ID and using the existing PriorityDiagnostic descriptors so the analyzer’s diagnostics are discoverable and consistent with the release metadata.
  • In PriorityGenerator.GetHintName, using only symbol.Name for the generated file name can cause collisions for nested types or types with the same name in different namespaces; consider including namespace and nesting (e.g., metadata name) in the hint name to ensure uniqueness.
  • The priority-sorting logic is currently implemented only inside MicrosoftDiContainer.SortByPriority; since the same semantics are now exposed via ArchitectureContext and multiple extension methods, it may be worthwhile to centralize this sorting behavior in a shared helper to avoid subtle divergence if the rules change later.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `PriorityUsageAnalyzer` uses the hard-coded diagnostic ID `GF_Priority_Usage_001`, whereas `AnalyzerReleases.Unshipped.md` registers `GF_Priority_001``GF_Priority_004`; consider aligning the ID and using the existing `PriorityDiagnostic` descriptors so the analyzer’s diagnostics are discoverable and consistent with the release metadata.
- In `PriorityGenerator.GetHintName`, using only `symbol.Name` for the generated file name can cause collisions for nested types or types with the same name in different namespaces; consider including namespace and nesting (e.g., metadata name) in the hint name to ensure uniqueness.
- The priority-sorting logic is currently implemented only inside `MicrosoftDiContainer.SortByPriority`; since the same semantics are now exposed via `ArchitectureContext` and multiple extension methods, it may be worthwhile to centralize this sorting behavior in a shared helper to avoid subtle divergence if the rules change later.

## Individual Comments

### Comment 1
<location path="GFramework.Core/ioc/MicrosoftDiContainer.cs" line_range="638-595" />
<code_context>
+        var list = services.ToList();
+
+        // 稳定排序:相同优先级保持注册顺序
+        list.Sort((a, b) =>
+        {
+            var priorityA = a is IPrioritized pa ? pa.Priority : 0;
+            var priorityB = b is IPrioritized pb ? pb.Priority : 0;
+            return priorityA.CompareTo(priorityB); // 升序
+        });
+
+        return list;
+    }
+
</code_context>
<issue_to_address>
**issue (bug_risk):** The use of List.Sort here contradicts the "stable sort" guarantee in the comment and tests.

Because List<T>.Sort is not stable, items with the same Priority may not preserve registration order, causing flaky behavior that contradicts the documented contract. To ensure stability, use an approach that includes the original index in the sort key (e.g., sort by (priority, index)) or use OrderBy with an index selector instead of List.Sort.
</issue_to_address>

### Comment 2
<location path="GFramework.SourceGenerators/bases/PriorityGenerator.cs" line_range="115-122" />
<code_context>
+            ? $"<{string.Join(", ", symbol.TypeParameters.Select(tp => tp.Name))}>"
+            : string.Empty;
+
+        sb.AppendLine(
+            $"partial class {symbol.Name}{typeParameters} : global::GFramework.Core.Abstractions.bases.IPrioritized");
+        sb.AppendLine("{");
+        sb.AppendLine("    /// <summary>");
+        sb.AppendLine($"    /// 获取优先级值: {priorityValue}");
+        sb.AppendLine("    /// </summary>");
+        sb.AppendLine($"    public int Priority => {priorityValue};");
+        sb.AppendLine("}");
+
+        return sb.ToString().TrimEnd();
</code_context>
<issue_to_address>
**issue:** Generated partial class does not account for nesting, which will break for nested types.

For nested classes, `symbol.Name` only gives the innermost type name, so the generator emits a top-level partial in the namespace instead of matching the original nesting (e.g., `OuterClass.NestedSystem`). This will fail to compile for nested (and some generic/nested) types. Consider emitting the full containing type hierarchy (e.g., wrapping in partials for containing types or constructing the full nested type name) so the generated partial structurally matches the original declaration.
</issue_to_address>

### Comment 3
<location path="GFramework.Core/ioc/MicrosoftDiContainer.cs" line_range="613" />
<code_context>
+
+    /// <summary>
+    /// 获取指定类型的所有实例,并按优先级排序
+    /// 实现 IPrioritized 接口的服务将按值越小优先级越高)
+    /// 未实现 IPrioritized 的服务将使用默认优先级 0
+    /// </summary>
</code_context>
<issue_to_address>
**nitpick (typo):** Minor typo in XML documentation for GetAllByPriority(Type).

The Chinese summary line is missing an opening parenthesis before “值”, e.g. it should read “按优先级排序(数值越小优先级越高)” to be clear and grammatically correct.
</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 thread GFramework.Core/ioc/MicrosoftDiContainer.cs
Comment thread GFramework.SourceGenerators/bases/PriorityGenerator.cs
Comment thread GFramework.Core/ioc/MicrosoftDiContainer.cs Outdated
- 修改 MicrosoftDiContainer 中 GetAllByPriority 方法的排序逻辑,使用 OrderBy 确保稳定排序
- 修正注释中的中文描述,明确优先级排序规则
- 将 PriorityUsageAnalyzer 中的硬编码诊断规则替换为统一的 PriorityDiagnostic
- 在 PriorityGenerator 中添加对嵌套类的支持检查,报告 GF_Priority_005 错误
- 改进生成文件的命名策略,使用完整元数据名称避免冲突
- 更新 AnalyzerReleases.Unshipped.md 文档,添加新的诊断规则说明
- 移除 PriorityGeneratorSnapshotTests 中关于嵌套类的测试用例
@GeWuYou GeWuYou merged commit 16d8cad into main Mar 5, 2026
8 checks passed
@GeWuYou GeWuYou deleted the feat/add-priority-service-resolution branch March 5, 2026 14:53
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