From f8c39e46a54da02e64b745612174013f354e0f31 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:29:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(architecture):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=8C=89=E4=BC=98=E5=85=88=E7=BA=A7=E8=8E=B7=E5=8F=96=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=AE=9E=E4=BE=8B=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 ArchitectureContext 中添加 GetServicesByPriority、GetSystemsByPriority、 GetModelsByPriority 和 GetUtilitiesByPriority 方法 - 在 ContextAwareServiceExtensions 中添加对应的扩展方法支持按优先级获取实例 - 在 MicrosoftDiContainer 中实现 GetAllByPriority 方法和 SortByPriority 排序逻辑 - 在抽象层定义 IPrioritized 接口用于标记可排序的服务组件 - 为 PauseToken 添加完整的相等性比较和字符串转换方法 - 添加全面的单元测试验证优先级排序功能的正确性 --- .../architecture/IArchitectureContext.cs | 32 +++ .../bases/IPrioritized.cs | 17 ++ .../ioc/IIocContainer.cs | 18 ++ .../pause/PauseToken.cs | 33 ++- .../architecture/ArchitectureServicesTests.cs | 20 ++ .../architecture/GameContextTests.cs | 20 ++ .../architecture/PriorityServiceTests.cs | 249 ++++++++++++++++++ .../ioc/MicrosoftDiContainerTests.cs | 228 ++++++++++++++++ .../architecture/ArchitectureContext.cs | 44 ++++ .../ContextAwareServiceExtensions.cs | 60 +++++ GFramework.Core/ioc/MicrosoftDiContainer.cs | 51 ++++ 11 files changed, 771 insertions(+), 1 deletion(-) create mode 100644 GFramework.Core.Abstractions/bases/IPrioritized.cs create mode 100644 GFramework.Core.Tests/architecture/PriorityServiceTests.cs diff --git a/GFramework.Core.Abstractions/architecture/IArchitectureContext.cs b/GFramework.Core.Abstractions/architecture/IArchitectureContext.cs index c0d5d05..0558b0d 100644 --- a/GFramework.Core.Abstractions/architecture/IArchitectureContext.cs +++ b/GFramework.Core.Abstractions/architecture/IArchitectureContext.cs @@ -71,6 +71,38 @@ public interface IArchitectureContext /// 所有符合条件的工具类实例列表 IReadOnlyList GetUtilities() where TUtility : class, IUtility; + /// + /// 获取指定类型的所有服务实例,并按优先级排序 + /// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高) + /// + /// 服务类型 + /// 按优先级排序后的服务实例列表 + IReadOnlyList GetServicesByPriority() where TService : class; + + /// + /// 获取指定类型的所有系统实例,并按优先级排序 + /// 实现 IPrioritized 接口的系统将按优先级排序(数值越小优先级越高) + /// + /// 系统类型,必须继承自ISystem接口 + /// 按优先级排序后的系统实例列表 + IReadOnlyList GetSystemsByPriority() where TSystem : class, ISystem; + + /// + /// 获取指定类型的所有模型实例,并按优先级排序 + /// 实现 IPrioritized 接口的模型将按优先级排序(数值越小优先级越高) + /// + /// 模型类型,必须继承自IModel接口 + /// 按优先级排序后的模型实例列表 + IReadOnlyList GetModelsByPriority() where TModel : class, IModel; + + /// + /// 获取指定类型的所有工具类实例,并按优先级排序 + /// 实现 IPrioritized 接口的工具将按优先级排序(数值越小优先级越高) + /// + /// 工具类类型,必须继承自IUtility接口 + /// 按优先级排序后的工具类实例列表 + IReadOnlyList GetUtilitiesByPriority() where TUtility : class, IUtility; + /// /// 发送一个命令 /// diff --git a/GFramework.Core.Abstractions/bases/IPrioritized.cs b/GFramework.Core.Abstractions/bases/IPrioritized.cs new file mode 100644 index 0000000..be0c5a7 --- /dev/null +++ b/GFramework.Core.Abstractions/bases/IPrioritized.cs @@ -0,0 +1,17 @@ +namespace GFramework.Core.Abstractions.bases; + +/// +/// 定义具有优先级的对象接口。 +/// 数值越小优先级越高,越先执行。 +/// 用于控制服务、系统等组件的执行顺序。 +/// +public interface IPrioritized +{ + /// + /// 获取优先级值。 + /// 数值越小优先级越高。 + /// 默认优先级为 0。 + /// 建议范围:-1000 到 1000。 + /// + int Priority { get; } +} \ No newline at end of file diff --git a/GFramework.Core.Abstractions/ioc/IIocContainer.cs b/GFramework.Core.Abstractions/ioc/IIocContainer.cs index 9a07c8d..8e87a2a 100644 --- a/GFramework.Core.Abstractions/ioc/IIocContainer.cs +++ b/GFramework.Core.Abstractions/ioc/IIocContainer.cs @@ -165,6 +165,24 @@ public interface IIocContainer : IContextAware /// 按指定方式排序后的实例列表 IReadOnlyList GetAllSorted(Comparison comparison) where T : class; + /// + /// 获取指定类型的所有实例,并按优先级排序 + /// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高) + /// 未实现 IPrioritized 的服务将使用默认优先级 0 + /// + /// 期望获取的实例类型 + /// 按优先级排序后的实例列表 + IReadOnlyList GetAllByPriority() where T : class; + + /// + /// 获取指定类型的所有实例,并按优先级排序 + /// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高) + /// 未实现 IPrioritized 的服务将使用默认优先级 0 + /// + /// 期望获取的实例类型 + /// 按优先级排序后的实例列表 + IReadOnlyList GetAllByPriority(Type type); + #endregion #region Utility Methods diff --git a/GFramework.Core.Abstractions/pause/PauseToken.cs b/GFramework.Core.Abstractions/pause/PauseToken.cs index 1b27802..be0c345 100644 --- a/GFramework.Core.Abstractions/pause/PauseToken.cs +++ b/GFramework.Core.Abstractions/pause/PauseToken.cs @@ -18,7 +18,7 @@ public readonly struct PauseToken : IEquatable /// /// 创建暂停令牌 /// - /// 令牌 ID + /// 令牌 ID,用于唯一标识暂停请求 public PauseToken(Guid id) { Id = id; @@ -27,17 +27,48 @@ public readonly struct PauseToken : IEquatable /// /// 创建无效令牌 /// + /// 返回一个 ID 为 Guid.Empty 的无效暂停令牌 public static PauseToken Invalid => new(Guid.Empty); + /// + /// 判断当前令牌是否与另一个令牌相等 + /// + /// 要比较的另一个暂停令牌 + /// 如果两个令牌的 ID 相同则返回 true,否则返回 false public bool Equals(PauseToken other) => Id.Equals(other.Id); + /// + /// 判断当前对象是否为暂停令牌类型并与其相等 + /// + /// 要比较的对象 + /// 如果对象是 PauseToken 类型且 ID 相同则返回 true,否则返回 false public override bool Equals(object? obj) => obj is PauseToken other && Equals(other); + /// + /// 获取令牌的哈希码 + /// + /// 基于令牌 ID 计算的哈希值 public override int GetHashCode() => Id.GetHashCode(); + /// + /// 重载等于运算符,判断两个暂停令牌是否相等 + /// + /// 左侧暂停令牌 + /// 右侧暂停令牌 + /// 如果两个令牌相等则返回 true,否则返回 false public static bool operator ==(PauseToken left, PauseToken right) => left.Equals(right); + /// + /// 重载不等于运算符,判断两个暂停令牌是否不相等 + /// + /// 左侧暂停令牌 + /// 右侧暂停令牌 + /// 如果两个令牌不相等则返回 true,否则返回 false public static bool operator !=(PauseToken left, PauseToken right) => !left.Equals(right); + /// + /// 将暂停令牌转换为字符串表示形式 + /// + /// 包含令牌 ID 信息的字符串 public override string ToString() => $"PauseToken({Id})"; } \ No newline at end of file diff --git a/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs b/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs index 42e2833..efe5aad 100644 --- a/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs +++ b/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs @@ -340,6 +340,26 @@ public class TestArchitectureContextV3 : IArchitectureContext return _container.GetAll(); } + public IReadOnlyList GetServicesByPriority() where TService : class + { + return _container.GetAllByPriority(); + } + + public IReadOnlyList GetSystemsByPriority() where TSystem : class, ISystem + { + return _container.GetAllByPriority(); + } + + public IReadOnlyList GetModelsByPriority() where TModel : class, IModel + { + return _container.GetAllByPriority(); + } + + public IReadOnlyList GetUtilitiesByPriority() where TUtility : class, IUtility + { + return _container.GetAllByPriority(); + } + public void SendEvent() where TEvent : new() { } diff --git a/GFramework.Core.Tests/architecture/GameContextTests.cs b/GFramework.Core.Tests/architecture/GameContextTests.cs index 93f627f..7ab2400 100644 --- a/GFramework.Core.Tests/architecture/GameContextTests.cs +++ b/GFramework.Core.Tests/architecture/GameContextTests.cs @@ -338,6 +338,26 @@ public class TestArchitectureContext : IArchitectureContext return _container.GetAll(); } + public IReadOnlyList GetServicesByPriority() where TService : class + { + return _container.GetAllByPriority(); + } + + public IReadOnlyList GetSystemsByPriority() where TSystem : class, ISystem + { + return _container.GetAllByPriority(); + } + + public IReadOnlyList GetModelsByPriority() where TModel : class, IModel + { + return _container.GetAllByPriority(); + } + + public IReadOnlyList GetUtilitiesByPriority() where TUtility : class, IUtility + { + return _container.GetAllByPriority(); + } + /// /// 发送事件 /// diff --git a/GFramework.Core.Tests/architecture/PriorityServiceTests.cs b/GFramework.Core.Tests/architecture/PriorityServiceTests.cs new file mode 100644 index 0000000..90ba4bc --- /dev/null +++ b/GFramework.Core.Tests/architecture/PriorityServiceTests.cs @@ -0,0 +1,249 @@ +using System.Reflection; +using GFramework.Core.Abstractions.bases; +using GFramework.Core.Abstractions.model; +using GFramework.Core.Abstractions.system; +using GFramework.Core.Abstractions.utility; +using GFramework.Core.ioc; +using GFramework.Core.logging; +using GFramework.Core.model; +using GFramework.Core.system; +using NUnit.Framework; + +namespace GFramework.Core.Tests.architecture; + +/// +/// 优先级服务排序的集成测试 +/// 测试完整的架构集成场景 +/// +[TestFixture] +public class PriorityServiceTests +{ + [SetUp] + public void SetUp() + { + LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider(); + _container = new MicrosoftDiContainer(); + + // 初始化 logger 字段 + var loggerField = typeof(MicrosoftDiContainer).GetField("_logger", + BindingFlags.NonPublic | BindingFlags.Instance); + loggerField?.SetValue(_container, + LoggerFactoryResolver.Provider.CreateLogger(nameof(MicrosoftDiContainer))); + } + + private MicrosoftDiContainer _container = null!; + + /// + /// 测试系统按优先级排序 + /// + [Test] + public void Systems_Should_Be_Sorted_By_Priority() + { + // Arrange + _container.Register(new PriorityTestSystemC()); + _container.Register(new PriorityTestSystemA()); + _container.Register(new PriorityTestSystemB()); + _container.Freeze(); + + // Act + var systems = _container.GetAllByPriority(); + + // Assert + Assert.That(systems, Has.Count.EqualTo(3)); + Assert.That(systems[0], Is.InstanceOf()); // Priority = 10 + Assert.That(systems[1], Is.InstanceOf()); // Priority = 20 + Assert.That(systems[2], Is.InstanceOf()); // Priority = 30 + } + + /// + /// 测试模型按优先级排序 + /// + [Test] + public void Models_Should_Be_Sorted_By_Priority() + { + // Arrange + _container.Register(new PriorityTestModelC()); + _container.Register(new PriorityTestModelA()); + _container.Register(new PriorityTestModelB()); + _container.Freeze(); + + // Act + var models = _container.GetAllByPriority(); + + // Assert + Assert.That(models, Has.Count.EqualTo(3)); + Assert.That(models[0], Is.InstanceOf()); // Priority = 10 + Assert.That(models[1], Is.InstanceOf()); // Priority = 20 + Assert.That(models[2], Is.InstanceOf()); // Priority = 30 + } + + /// + /// 测试工具按优先级排序 + /// + [Test] + public void Utilities_Should_Be_Sorted_By_Priority() + { + // Arrange + _container.Register(new PriorityTestUtilityC()); + _container.Register(new PriorityTestUtilityA()); + _container.Register(new PriorityTestUtilityB()); + _container.Freeze(); + + // Act + var utilities = _container.GetAllByPriority(); + + // Assert + Assert.That(utilities, Has.Count.EqualTo(3)); + Assert.That(utilities[0], Is.InstanceOf()); // Priority = 10 + Assert.That(utilities[1], Is.InstanceOf()); // Priority = 20 + Assert.That(utilities[2], Is.InstanceOf()); // Priority = 30 + } + + /// + /// 测试混合优先级和非优先级服务 + /// + [Test] + public void Mixed_Prioritized_And_Non_Prioritized_Should_Work() + { + // Arrange + _container.Register(new MixedTestSystemWithPriority()); + _container.Register(new MixedTestSystemWithoutPriority()); + _container.Register(new MixedTestSystemNegativePriority()); + _container.Freeze(); + + // Act + var systems = _container.GetAllByPriority(); + + // Assert + Assert.That(systems, Has.Count.EqualTo(3)); + Assert.That(systems[0], Is.InstanceOf()); // -10 + Assert.That(systems[1], Is.InstanceOf()); // 0 (默认) + Assert.That(systems[2], Is.InstanceOf()); // 10 + } +} + +#region Test Interfaces + +public interface IPriorityTestSystem : ISystem +{ +} + +public interface IPriorityTestModel : IModel +{ +} + +public interface IPriorityTestUtility : IUtility +{ +} + +public interface IMixedTestSystem : ISystem +{ +} + +#endregion + +#region Test Systems + +public class PriorityTestSystemA : AbstractSystem, IPriorityTestSystem, IPrioritized +{ + public int Priority => 10; + + protected override void OnInit() + { + } +} + +public class PriorityTestSystemB : AbstractSystem, IPriorityTestSystem, IPrioritized +{ + public int Priority => 20; + + protected override void OnInit() + { + } +} + +public class PriorityTestSystemC : AbstractSystem, IPriorityTestSystem, IPrioritized +{ + public int Priority => 30; + + protected override void OnInit() + { + } +} + +public class MixedTestSystemWithPriority : AbstractSystem, IMixedTestSystem, IPrioritized +{ + public int Priority => 10; + + protected override void OnInit() + { + } +} + +public class MixedTestSystemWithoutPriority : AbstractSystem, IMixedTestSystem +{ + protected override void OnInit() + { + } +} + +public class MixedTestSystemNegativePriority : AbstractSystem, IMixedTestSystem, IPrioritized +{ + public int Priority => -10; + + protected override void OnInit() + { + } +} + +#endregion + +#region Test Models + +public class PriorityTestModelA : AbstractModel, IPriorityTestModel, IPrioritized +{ + public int Priority => 10; + + protected override void OnInit() + { + } +} + +public class PriorityTestModelB : AbstractModel, IPriorityTestModel, IPrioritized +{ + public int Priority => 20; + + protected override void OnInit() + { + } +} + +public class PriorityTestModelC : AbstractModel, IPriorityTestModel, IPrioritized +{ + public int Priority => 30; + + protected override void OnInit() + { + } +} + +#endregion + +#region Test Utilities + +public class PriorityTestUtilityA : IPriorityTestUtility, IPrioritized +{ + public int Priority => 10; +} + +public class PriorityTestUtilityB : IPriorityTestUtility, IPrioritized +{ + public int Priority => 20; +} + +public class PriorityTestUtilityC : IPriorityTestUtility, IPrioritized +{ + public int Priority => 30; +} + +#endregion \ No newline at end of file diff --git a/GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs b/GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs index fba566f..e10c8d0 100644 --- a/GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs +++ b/GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs @@ -1,4 +1,5 @@ using System.Reflection; +using GFramework.Core.Abstractions.bases; using GFramework.Core.ioc; using GFramework.Core.logging; using GFramework.Core.Tests.system; @@ -433,6 +434,200 @@ public class MicrosoftDiContainerTests // Assert Assert.DoesNotThrow(() => Task.WaitAll(tasks)); } + + /// + /// 测试按优先级排序功能 - 升序排序 + /// + [Test] + public void GetAllByPriority_Should_Sort_By_Priority_Ascending() + { + // Arrange + var service1 = new PrioritizedService { Priority = 30 }; + var service2 = new PrioritizedService { Priority = 10 }; + var service3 = new PrioritizedService { Priority = 20 }; + + _container.Register(service1); + _container.Register(service2); + _container.Register(service3); + _container.Freeze(); + + // Act + var services = _container.GetAllByPriority(); + + // Assert + Assert.That(services, Has.Count.EqualTo(3)); + Assert.That(services[0].Priority, Is.EqualTo(10)); // 最小优先级在前 + Assert.That(services[1].Priority, Is.EqualTo(20)); + Assert.That(services[2].Priority, Is.EqualTo(30)); + } + + /// + /// 测试未实现 IPrioritized 的服务使用默认优先级 0 + /// + [Test] + public void GetAllByPriority_Should_Use_Default_Priority_For_Non_Prioritized() + { + // Arrange + var service1 = new PrioritizedService { Priority = 10 }; + var service2 = new NonPrioritizedService(); + var service3 = new PrioritizedService { Priority = -10 }; + + _container.Register(service1); + _container.Register(service2); + _container.Register(service3); + _container.Freeze(); + + // Act + var services = _container.GetAllByPriority(); + + // Assert + Assert.That(services, Has.Count.EqualTo(3)); + Assert.That(services[0], Is.SameAs(service3)); // -10 + Assert.That(services[1], Is.SameAs(service2)); // 0 (默认) + Assert.That(services[2], Is.SameAs(service1)); // 10 + } + + /// + /// 测试相同优先级保持注册顺序(稳定排序) + /// + [Test] + public void GetAllByPriority_Should_Preserve_Registration_Order_For_Equal_Priorities() + { + // Arrange + var service1 = new PrioritizedService { Priority = 10, Name = "First" }; + var service2 = new PrioritizedService { Priority = 10, Name = "Second" }; + var service3 = new PrioritizedService { Priority = 10, Name = "Third" }; + + _container.Register(service1); + _container.Register(service2); + _container.Register(service3); + _container.Freeze(); + + // Act + var services = _container.GetAllByPriority(); + + // Assert + Assert.That(services, Has.Count.EqualTo(3)); + Assert.That(services[0].Name, Is.EqualTo("First")); + Assert.That(services[1].Name, Is.EqualTo("Second")); + Assert.That(services[2].Name, Is.EqualTo("Third")); + } + + /// + /// 测试空列表处理 + /// + [Test] + public void GetAllByPriority_Should_Handle_Empty_List() + { + // Arrange + _container.Freeze(); + + // Act + var services = _container.GetAllByPriority(); + + // Assert + Assert.That(services, Is.Empty); + } + + /// + /// 测试单项列表处理 + /// + [Test] + public void GetAllByPriority_Should_Handle_Single_Item() + { + // Arrange + var service = new PrioritizedService { Priority = 42 }; + _container.RegisterSingleton(service); + _container.Freeze(); + + // Act + var services = _container.GetAllByPriority(); + + // Assert + Assert.That(services, Has.Count.EqualTo(1)); + Assert.That(services[0], Is.SameAs(service)); + } + + /// + /// 测试负数优先级处理 + /// + [Test] + public void GetAllByPriority_Should_Handle_Negative_Priorities() + { + // Arrange + var service1 = new PrioritizedService { Priority = -100 }; + var service2 = new PrioritizedService { Priority = 0 }; + var service3 = new PrioritizedService { Priority = 100 }; + var service4 = new PrioritizedService { Priority = -50 }; + + _container.Register(service1); + _container.Register(service2); + _container.Register(service3); + _container.Register(service4); + _container.Freeze(); + + // Act + var services = _container.GetAllByPriority(); + + // Assert + Assert.That(services, Has.Count.EqualTo(4)); + Assert.That(services[0].Priority, Is.EqualTo(-100)); + Assert.That(services[1].Priority, Is.EqualTo(-50)); + Assert.That(services[2].Priority, Is.EqualTo(0)); + Assert.That(services[3].Priority, Is.EqualTo(100)); + } + + /// + /// 测试混合优先级和非优先级服务 + /// + [Test] + public void GetAllByPriority_Should_Handle_Mixed_Prioritized_And_Non_Prioritized() + { + // Arrange + var service1 = new PrioritizedService { Priority = 50, Name = "P50" }; + var service2 = new NonPrioritizedService { Name = "NP1" }; + var service3 = new PrioritizedService { Priority = -50, Name = "P-50" }; + var service4 = new NonPrioritizedService { Name = "NP2" }; + + _container.Register(service1); + _container.Register(service2); + _container.Register(service3); + _container.Register(service4); + _container.Freeze(); + + // Act + var services = _container.GetAllByPriority(); + + // Assert + Assert.That(services, Has.Count.EqualTo(4)); + Assert.That(services[0].Name, Is.EqualTo("P-50")); // -50 + Assert.That(services[1].Name, Is.EqualTo("NP1")); // 0 (默认) + Assert.That(services[2].Name, Is.EqualTo("NP2")); // 0 (默认) + Assert.That(services[3].Name, Is.EqualTo("P50")); // 50 + } + + /// + /// 测试 GetAllByPriority(Type) 重载方法 + /// + [Test] + public void GetAllByPriority_Type_Should_Sort_Correctly() + { + // Arrange + var service1 = new PrioritizedService { Priority = 30 }; + var service2 = new PrioritizedService { Priority = 10 }; + + _container.Register(service1); + _container.Register(service2); + _container.Freeze(); + + // Act + var services = _container.GetAllByPriority(typeof(IPrioritizedService)); + + // Assert + Assert.That(services, Has.Count.EqualTo(2)); + Assert.That(((IPrioritizedService)services[0]).Priority, Is.EqualTo(10)); + Assert.That(((IPrioritizedService)services[1]).Priority, Is.EqualTo(30)); + } } /// @@ -449,4 +644,37 @@ public sealed class TestService : IService /// 获取或设置优先级 /// public int Priority { get; set; } +} + +/// +/// 优先级服务接口 +/// +public interface IPrioritizedService : IPrioritized +{ + string? Name { get; set; } +} + +/// +/// 混合服务接口(用于测试优先级和非优先级混合) +/// +public interface IMixedService +{ + string? Name { get; set; } +} + +/// +/// 实现优先级的服务 +/// +public sealed class PrioritizedService : IPrioritizedService, IMixedService +{ + public int Priority { get; set; } + public string? Name { get; set; } +} + +/// +/// 不实现优先级的服务 +/// +public sealed class NonPrioritizedService : IMixedService +{ + public string? Name { get; set; } } \ No newline at end of file diff --git a/GFramework.Core/architecture/ArchitectureContext.cs b/GFramework.Core/architecture/ArchitectureContext.cs index 0e8e456..d021bdd 100644 --- a/GFramework.Core/architecture/ArchitectureContext.cs +++ b/GFramework.Core/architecture/ArchitectureContext.cs @@ -303,6 +303,50 @@ public class ArchitectureContext(IIocContainer container) : IArchitectureContext return _container.GetAll(); } + /// + /// 获取指定类型的所有服务实例,并按优先级排序 + /// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高) + /// + /// 服务类型 + /// 按优先级排序后的服务实例列表 + public IReadOnlyList GetServicesByPriority() where TService : class + { + return _container.GetAllByPriority(); + } + + /// + /// 获取指定类型的所有系统实例,并按优先级排序 + /// 实现 IPrioritized 接口的系统将按优先级排序(数值越小优先级越高) + /// + /// 系统类型 + /// 按优先级排序后的系统实例列表 + public IReadOnlyList GetSystemsByPriority() where TSystem : class, ISystem + { + return _container.GetAllByPriority(); + } + + /// + /// 获取指定类型的所有模型实例,并按优先级排序 + /// 实现 IPrioritized 接口的模型将按优先级排序(数值越小优先级越高) + /// + /// 模型类型 + /// 按优先级排序后的模型实例列表 + public IReadOnlyList GetModelsByPriority() where TModel : class, IModel + { + return _container.GetAllByPriority(); + } + + /// + /// 获取指定类型的所有工具实例,并按优先级排序 + /// 实现 IPrioritized 接口的工具将按优先级排序(数值越小优先级越高) + /// + /// 工具类型 + /// 按优先级排序后的工具实例列表 + public IReadOnlyList GetUtilitiesByPriority() where TUtility : class, IUtility + { + return _container.GetAllByPriority(); + } + #endregion #region Command Execution diff --git a/GFramework.Core/extensions/ContextAwareServiceExtensions.cs b/GFramework.Core/extensions/ContextAwareServiceExtensions.cs index e3a6f22..514700b 100644 --- a/GFramework.Core/extensions/ContextAwareServiceExtensions.cs +++ b/GFramework.Core/extensions/ContextAwareServiceExtensions.cs @@ -133,5 +133,65 @@ public static class ContextAwareServiceExtensions return context.GetUtilities(); } + /// + /// 获取指定类型的所有服务实例,并按优先级排序 + /// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高) + /// + /// 服务类型 + /// 上下文感知对象 + /// 按优先级排序后的服务实例列表 + public static IReadOnlyList GetServicesByPriority(this IContextAware contextAware) + where TService : class + { + ArgumentNullException.ThrowIfNull(contextAware); + var context = contextAware.GetContext(); + return context.GetServicesByPriority(); + } + + /// + /// 获取指定类型的所有系统实例,并按优先级排序 + /// 实现 IPrioritized 接口的系统将按优先级排序(数值越小优先级越高) + /// + /// 系统类型 + /// 上下文感知对象 + /// 按优先级排序后的系统实例列表 + public static IReadOnlyList GetSystemsByPriority(this IContextAware contextAware) + where TSystem : class, ISystem + { + ArgumentNullException.ThrowIfNull(contextAware); + var context = contextAware.GetContext(); + return context.GetSystemsByPriority(); + } + + /// + /// 获取指定类型的所有模型实例,并按优先级排序 + /// 实现 IPrioritized 接口的模型将按优先级排序(数值越小优先级越高) + /// + /// 模型类型 + /// 上下文感知对象 + /// 按优先级排序后的模型实例列表 + public static IReadOnlyList GetModelsByPriority(this IContextAware contextAware) + where TModel : class, IModel + { + ArgumentNullException.ThrowIfNull(contextAware); + var context = contextAware.GetContext(); + return context.GetModelsByPriority(); + } + + /// + /// 获取指定类型的所有工具实例,并按优先级排序 + /// 实现 IPrioritized 接口的工具将按优先级排序(数值越小优先级越高) + /// + /// 工具类型 + /// 上下文感知对象 + /// 按优先级排序后的工具实例列表 + public static IReadOnlyList GetUtilitiesByPriority(this IContextAware contextAware) + where TUtility : class, IUtility + { + ArgumentNullException.ThrowIfNull(contextAware); + var context = contextAware.GetContext(); + return context.GetUtilitiesByPriority(); + } + #endregion } \ No newline at end of file diff --git a/GFramework.Core/ioc/MicrosoftDiContainer.cs b/GFramework.Core/ioc/MicrosoftDiContainer.cs index 68b1a86..d591baa 100644 --- a/GFramework.Core/ioc/MicrosoftDiContainer.cs +++ b/GFramework.Core/ioc/MicrosoftDiContainer.cs @@ -1,3 +1,4 @@ +using GFramework.Core.Abstractions.bases; using GFramework.Core.Abstractions.ioc; using GFramework.Core.Abstractions.logging; using GFramework.Core.Abstractions.system; @@ -594,6 +595,56 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null) return list; } + /// + /// 获取指定类型的所有实例,并按优先级排序 + /// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高) + /// 未实现 IPrioritized 的服务将使用默认优先级 0 + /// + /// 期望获取的实例类型 + /// 按优先级排序后的实例列表 + public IReadOnlyList GetAllByPriority() where T : class + { + var services = GetAll(); + return SortByPriority(services); + } + + /// + /// 获取指定类型的所有实例,并按优先级排序 + /// 实现 IPrioritized 接口的服务将按值越小优先级越高) + /// 未实现 IPrioritized 的服务将使用默认优先级 0 + /// + /// 期望获取的实例类型 + /// 按优先级排序后的实例列表 + public IReadOnlyList GetAllByPriority(Type type) + { + var services = GetAll(type); + return SortByPriority(services); + } + + /// + /// 按优先级排序服务列表 + /// 实现 IPrioritized 接口的服务按 Priority 属性排序(升序) + /// 未实现接口的服务使用默认优先级 0 + /// 相同优先级保持原有注册顺序(稳定排序) + /// + private static IReadOnlyList SortByPriority(IReadOnlyList services) where T : class + { + 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; + } + #endregion #region Utility