diff --git a/GFramework.Core/ioc/MicrosoftDiContainer.cs b/GFramework.Core/ioc/MicrosoftDiContainer.cs
index d591baa..7ff5d20 100644
--- a/GFramework.Core/ioc/MicrosoftDiContainer.cs
+++ b/GFramework.Core/ioc/MicrosoftDiContainer.cs
@@ -610,7 +610,7 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null)
///
/// 获取指定类型的所有实例,并按优先级排序
- /// 实现 IPrioritized 接口的服务将按值越小优先级越高)
+ /// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高)
/// 未实现 IPrioritized 的服务将使用默认优先级 0
///
/// 期望获取的实例类型
@@ -632,17 +632,16 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null)
if (services.Count <= 1)
return services;
- 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;
+ // 使用 OrderBy 确保稳定排序(相同优先级保持原有顺序)
+ return services
+ .Select((service, index) => new { Service = service, Index = index })
+ .OrderBy(x =>
+ {
+ var priority = x.Service is IPrioritized p ? p.Priority : 0;
+ return (priority, x.Index); // 先按优先级,再按索引
+ })
+ .Select(x => x.Service)
+ .ToList();
}
#endregion
diff --git a/GFramework.SourceGenerators.Tests/bases/PriorityGeneratorSnapshotTests.cs b/GFramework.SourceGenerators.Tests/bases/PriorityGeneratorSnapshotTests.cs
index c5c7c56..d5ac1f1 100644
--- a/GFramework.SourceGenerators.Tests/bases/PriorityGeneratorSnapshotTests.cs
+++ b/GFramework.SourceGenerators.Tests/bases/PriorityGeneratorSnapshotTests.cs
@@ -212,55 +212,4 @@ public class PriorityGeneratorSnapshotTests
"PriorityGenerator",
"GenericClass"));
}
-
- ///
- /// 测试嵌套类支持
- ///
- [Test]
- public async Task Snapshot_NestedClass()
- {
- const string source = """
- using System;
-
- namespace GFramework.SourceGenerators.Abstractions.bases
- {
- [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
- public sealed class PriorityAttribute : Attribute
- {
- public int Value { get; }
- public PriorityAttribute(int value) { Value = value; }
- }
- }
-
- namespace GFramework.Core.Abstractions.bases
- {
- public interface IPrioritized
- {
- int Priority { get; }
- }
- }
-
- namespace TestApp
- {
- using GFramework.SourceGenerators.Abstractions.bases;
-
- public class OuterClass
- {
- [Priority(30)]
- public partial class NestedSystem
- {
- }
- }
- }
- """;
-
- await GeneratorSnapshotTest.RunAsync(
- source,
- Path.Combine(
- TestContext.CurrentContext.TestDirectory,
- "bases",
- "snapshots",
- "PriorityGenerator",
- "NestedClass"));
- }
}
\ No newline at end of file
diff --git a/GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md b/GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md
index ce9dd59..d3e0463 100644
--- a/GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md
+++ b/GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md
@@ -11,4 +11,5 @@
GF_Priority_002 | GFramework.Priority | Warning | PriorityDiagnostic
GF_Priority_003 | GFramework.Priority | Error | PriorityDiagnostic
GF_Priority_004 | GFramework.Priority | Error | PriorityDiagnostic
+ GF_Priority_005 | GFramework.Priority | Error | PriorityDiagnostic
GF_Priority_Usage_001 | GFramework.Usage | Info | PriorityUsageAnalyzer
\ No newline at end of file
diff --git a/GFramework.SourceGenerators/analyzers/PriorityUsageAnalyzer.cs b/GFramework.SourceGenerators/analyzers/PriorityUsageAnalyzer.cs
index 37d82a7..33a770a 100644
--- a/GFramework.SourceGenerators/analyzers/PriorityUsageAnalyzer.cs
+++ b/GFramework.SourceGenerators/analyzers/PriorityUsageAnalyzer.cs
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
+using GFramework.SourceGenerators.diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
@@ -11,27 +12,11 @@ namespace GFramework.SourceGenerators.analyzers;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class PriorityUsageAnalyzer : DiagnosticAnalyzer
{
- ///
- /// 诊断 ID
- ///
- private const string DiagnosticId = "GF_Priority_Usage_001";
-
- ///
- /// 诊断规则
- ///
- private static readonly DiagnosticDescriptor Rule = new(
- id: DiagnosticId,
- title: "建议使用 GetAllByPriority",
- messageFormat: "类型 '{0}' 实现了 IPrioritized 接口,建议使用 GetAllByPriority<{0}>() 而非 GetAll<{0}>()",
- category: "GFramework.Usage",
- defaultSeverity: DiagnosticSeverity.Info,
- isEnabledByDefault: true,
- description: "当获取实现了 IPrioritized 接口的服务时,应使用 GetAllByPriority 方法以确保按优先级排序。");
-
///
/// 支持的诊断规则
///
- public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+ public override ImmutableArray SupportedDiagnostics =>
+ ImmutableArray.Create(PriorityDiagnostic.SuggestGetAllByPriority);
///
/// 初始化分析器
@@ -112,7 +97,7 @@ public sealed class PriorityUsageAnalyzer : DiagnosticAnalyzer
// 报告诊断
var diagnostic = Diagnostic.Create(
- Rule,
+ PriorityDiagnostic.SuggestGetAllByPriority,
invocation.Syntax.GetLocation(),
typeArgument.ToDisplayString());
diff --git a/GFramework.SourceGenerators/bases/PriorityGenerator.cs b/GFramework.SourceGenerators/bases/PriorityGenerator.cs
index a509347..69a9acd 100644
--- a/GFramework.SourceGenerators/bases/PriorityGenerator.cs
+++ b/GFramework.SourceGenerators/bases/PriorityGenerator.cs
@@ -45,8 +45,18 @@ public sealed class PriorityGenerator : MetadataAttributeClassGeneratorBase
return false;
}
- // 2. 必须是 partial
- if (!syntax.Modifiers.Any(SyntaxKind.PartialKeyword))
+ // 2. 不支持嵌套类
+ if (symbol.ContainingType != null)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(
+ PriorityDiagnostic.NestedClassNotSupported,
+ syntax.Identifier.GetLocation(),
+ symbol.Name));
+ return false;
+ }
+
+ // 3. 必须是 partial
+ if (syntax.Modifiers.All(m => m.Kind() != SyntaxKind.PartialKeyword))
{
context.ReportDiagnostic(Diagnostic.Create(
PriorityDiagnostic.MustBePartial,
@@ -55,7 +65,7 @@ public sealed class PriorityGenerator : MetadataAttributeClassGeneratorBase
return false;
}
- // 3. 检查是否已手动实现 IPrioritized
+ // 4. 检查是否已手动实现 IPrioritized
var iPrioritized = compilation.GetTypeByMetadataName(
$"{PathContests.CoreAbstractionsNamespace}.bases.IPrioritized");
@@ -68,7 +78,7 @@ public sealed class PriorityGenerator : MetadataAttributeClassGeneratorBase
return false;
}
- // 4. 验证特性参数
+ // 5. 验证特性参数
if (attr.ConstructorArguments.Length == 0 ||
attr.ConstructorArguments[0].Value is not int)
{
@@ -129,6 +139,15 @@ public sealed class PriorityGenerator : MetadataAttributeClassGeneratorBase
///
protected override string GetHintName(INamedTypeSymbol symbol)
{
- return $"{symbol.Name}.Priority.g.cs";
+ // 使用完整的元数据名称以避免冲突
+ var metadataName = symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
+ .Replace("global::", "")
+ .Replace("<", "_")
+ .Replace(">", "_")
+ .Replace(",", "_")
+ .Replace(" ", "")
+ .Replace(".", "_");
+
+ return $"{metadataName}.Priority.g.cs";
}
}
\ No newline at end of file
diff --git a/GFramework.SourceGenerators/diagnostics/PriorityDiagnostic.cs b/GFramework.SourceGenerators/diagnostics/PriorityDiagnostic.cs
index f9fb2d7..e63837d 100644
--- a/GFramework.SourceGenerators/diagnostics/PriorityDiagnostic.cs
+++ b/GFramework.SourceGenerators/diagnostics/PriorityDiagnostic.cs
@@ -60,4 +60,30 @@ internal static class PriorityDiagnostic
isEnabledByDefault: true,
description: "Priority 特性必须提供一个有效的整数值。"
);
+
+ ///
+ /// GF_Priority_005: Priority 不支持嵌套类
+ ///
+ public static readonly DiagnosticDescriptor NestedClassNotSupported = new(
+ id: "GF_Priority_005",
+ title: "Priority 不支持嵌套类",
+ messageFormat: "Priority 特性不支持嵌套类 '{0}',请将类移至顶层",
+ category: Category,
+ defaultSeverity: DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: "Priority 特性仅支持顶层类,不支持嵌套类。请将嵌套类移至命名空间级别。"
+ );
+
+ ///
+ /// GF_Priority_Usage_001: 建议使用 GetAllByPriority
+ ///
+ public static readonly DiagnosticDescriptor SuggestGetAllByPriority = new(
+ id: "GF_Priority_Usage_001",
+ title: "建议使用 GetAllByPriority",
+ messageFormat: "类型 '{0}' 实现了 IPrioritized 接口,建议使用 GetAllByPriority<{0}>() 而非 GetAll<{0}>()",
+ category: "GFramework.Usage",
+ defaultSeverity: DiagnosticSeverity.Info,
+ isEnabledByDefault: true,
+ description: "当获取实现了 IPrioritized 接口的服务时,应使用 GetAllByPriority 方法以确保按优先级排序。"
+ );
}
\ No newline at end of file