mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
feat(architecture): 添加按优先级获取服务实例的功能
- 在 ArchitectureContext 中添加 GetServicesByPriority、GetSystemsByPriority、 GetModelsByPriority 和 GetUtilitiesByPriority 方法 - 在 ContextAwareServiceExtensions 中添加对应的扩展方法支持按优先级获取实例 - 在 MicrosoftDiContainer 中实现 GetAllByPriority 方法和 SortByPriority 排序逻辑 - 在抽象层定义 IPrioritized 接口用于标记可排序的服务组件 - 为 PauseToken 添加完整的相等性比较和字符串转换方法 - 添加全面的单元测试验证优先级排序功能的正确性
This commit is contained in:
parent
b4d17edeee
commit
f8c39e46a5
@ -71,6 +71,38 @@ public interface IArchitectureContext
|
||||
/// <returns>所有符合条件的工具类实例列表</returns>
|
||||
IReadOnlyList<TUtility> GetUtilities<TUtility>() where TUtility : class, IUtility;
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有服务实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高)
|
||||
/// </summary>
|
||||
/// <typeparam name="TService">服务类型</typeparam>
|
||||
/// <returns>按优先级排序后的服务实例列表</returns>
|
||||
IReadOnlyList<TService> GetServicesByPriority<TService>() where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有系统实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的系统将按优先级排序(数值越小优先级越高)
|
||||
/// </summary>
|
||||
/// <typeparam name="TSystem">系统类型,必须继承自ISystem接口</typeparam>
|
||||
/// <returns>按优先级排序后的系统实例列表</returns>
|
||||
IReadOnlyList<TSystem> GetSystemsByPriority<TSystem>() where TSystem : class, ISystem;
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有模型实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的模型将按优先级排序(数值越小优先级越高)
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">模型类型,必须继承自IModel接口</typeparam>
|
||||
/// <returns>按优先级排序后的模型实例列表</returns>
|
||||
IReadOnlyList<TModel> GetModelsByPriority<TModel>() where TModel : class, IModel;
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有工具类实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的工具将按优先级排序(数值越小优先级越高)
|
||||
/// </summary>
|
||||
/// <typeparam name="TUtility">工具类类型,必须继承自IUtility接口</typeparam>
|
||||
/// <returns>按优先级排序后的工具类实例列表</returns>
|
||||
IReadOnlyList<TUtility> GetUtilitiesByPriority<TUtility>() where TUtility : class, IUtility;
|
||||
|
||||
/// <summary>
|
||||
/// 发送一个命令
|
||||
/// </summary>
|
||||
|
||||
17
GFramework.Core.Abstractions/bases/IPrioritized.cs
Normal file
17
GFramework.Core.Abstractions/bases/IPrioritized.cs
Normal file
@ -0,0 +1,17 @@
|
||||
namespace GFramework.Core.Abstractions.bases;
|
||||
|
||||
/// <summary>
|
||||
/// 定义具有优先级的对象接口。
|
||||
/// 数值越小优先级越高,越先执行。
|
||||
/// 用于控制服务、系统等组件的执行顺序。
|
||||
/// </summary>
|
||||
public interface IPrioritized
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取优先级值。
|
||||
/// 数值越小优先级越高。
|
||||
/// 默认优先级为 0。
|
||||
/// 建议范围:-1000 到 1000。
|
||||
/// </summary>
|
||||
int Priority { get; }
|
||||
}
|
||||
@ -165,6 +165,24 @@ public interface IIocContainer : IContextAware
|
||||
/// <returns>按指定方式排序后的实例列表</returns>
|
||||
IReadOnlyList<T> GetAllSorted<T>(Comparison<T> comparison) where T : class;
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高)
|
||||
/// 未实现 IPrioritized 的服务将使用默认优先级 0
|
||||
/// </summary>
|
||||
/// <typeparam name="T">期望获取的实例类型</typeparam>
|
||||
/// <returns>按优先级排序后的实例列表</returns>
|
||||
IReadOnlyList<T> GetAllByPriority<T>() where T : class;
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高)
|
||||
/// 未实现 IPrioritized 的服务将使用默认优先级 0
|
||||
/// </summary>
|
||||
/// <param name="type">期望获取的实例类型</param>
|
||||
/// <returns>按优先级排序后的实例列表</returns>
|
||||
IReadOnlyList<object> GetAllByPriority(Type type);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utility Methods
|
||||
|
||||
@ -18,7 +18,7 @@ public readonly struct PauseToken : IEquatable<PauseToken>
|
||||
/// <summary>
|
||||
/// 创建暂停令牌
|
||||
/// </summary>
|
||||
/// <param name="id">令牌 ID</param>
|
||||
/// <param name="id">令牌 ID,用于唯一标识暂停请求</param>
|
||||
public PauseToken(Guid id)
|
||||
{
|
||||
Id = id;
|
||||
@ -27,17 +27,48 @@ public readonly struct PauseToken : IEquatable<PauseToken>
|
||||
/// <summary>
|
||||
/// 创建无效令牌
|
||||
/// </summary>
|
||||
/// <returns>返回一个 ID 为 Guid.Empty 的无效暂停令牌</returns>
|
||||
public static PauseToken Invalid => new(Guid.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前令牌是否与另一个令牌相等
|
||||
/// </summary>
|
||||
/// <param name="other">要比较的另一个暂停令牌</param>
|
||||
/// <returns>如果两个令牌的 ID 相同则返回 true,否则返回 false</returns>
|
||||
public bool Equals(PauseToken other) => Id.Equals(other.Id);
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前对象是否为暂停令牌类型并与其相等
|
||||
/// </summary>
|
||||
/// <param name="obj">要比较的对象</param>
|
||||
/// <returns>如果对象是 PauseToken 类型且 ID 相同则返回 true,否则返回 false</returns>
|
||||
public override bool Equals(object? obj) => obj is PauseToken other && Equals(other);
|
||||
|
||||
/// <summary>
|
||||
/// 获取令牌的哈希码
|
||||
/// </summary>
|
||||
/// <returns>基于令牌 ID 计算的哈希值</returns>
|
||||
public override int GetHashCode() => Id.GetHashCode();
|
||||
|
||||
/// <summary>
|
||||
/// 重载等于运算符,判断两个暂停令牌是否相等
|
||||
/// </summary>
|
||||
/// <param name="left">左侧暂停令牌</param>
|
||||
/// <param name="right">右侧暂停令牌</param>
|
||||
/// <returns>如果两个令牌相等则返回 true,否则返回 false</returns>
|
||||
public static bool operator ==(PauseToken left, PauseToken right) => left.Equals(right);
|
||||
|
||||
/// <summary>
|
||||
/// 重载不等于运算符,判断两个暂停令牌是否不相等
|
||||
/// </summary>
|
||||
/// <param name="left">左侧暂停令牌</param>
|
||||
/// <param name="right">右侧暂停令牌</param>
|
||||
/// <returns>如果两个令牌不相等则返回 true,否则返回 false</returns>
|
||||
public static bool operator !=(PauseToken left, PauseToken right) => !left.Equals(right);
|
||||
|
||||
/// <summary>
|
||||
/// 将暂停令牌转换为字符串表示形式
|
||||
/// </summary>
|
||||
/// <returns>包含令牌 ID 信息的字符串</returns>
|
||||
public override string ToString() => $"PauseToken({Id})";
|
||||
}
|
||||
@ -340,6 +340,26 @@ public class TestArchitectureContextV3 : IArchitectureContext
|
||||
return _container.GetAll<TUtility>();
|
||||
}
|
||||
|
||||
public IReadOnlyList<TService> GetServicesByPriority<TService>() where TService : class
|
||||
{
|
||||
return _container.GetAllByPriority<TService>();
|
||||
}
|
||||
|
||||
public IReadOnlyList<TSystem> GetSystemsByPriority<TSystem>() where TSystem : class, ISystem
|
||||
{
|
||||
return _container.GetAllByPriority<TSystem>();
|
||||
}
|
||||
|
||||
public IReadOnlyList<TModel> GetModelsByPriority<TModel>() where TModel : class, IModel
|
||||
{
|
||||
return _container.GetAllByPriority<TModel>();
|
||||
}
|
||||
|
||||
public IReadOnlyList<TUtility> GetUtilitiesByPriority<TUtility>() where TUtility : class, IUtility
|
||||
{
|
||||
return _container.GetAllByPriority<TUtility>();
|
||||
}
|
||||
|
||||
public void SendEvent<TEvent>() where TEvent : new()
|
||||
{
|
||||
}
|
||||
|
||||
@ -338,6 +338,26 @@ public class TestArchitectureContext : IArchitectureContext
|
||||
return _container.GetAll<TUtility>();
|
||||
}
|
||||
|
||||
public IReadOnlyList<TService> GetServicesByPriority<TService>() where TService : class
|
||||
{
|
||||
return _container.GetAllByPriority<TService>();
|
||||
}
|
||||
|
||||
public IReadOnlyList<TSystem> GetSystemsByPriority<TSystem>() where TSystem : class, ISystem
|
||||
{
|
||||
return _container.GetAllByPriority<TSystem>();
|
||||
}
|
||||
|
||||
public IReadOnlyList<TModel> GetModelsByPriority<TModel>() where TModel : class, IModel
|
||||
{
|
||||
return _container.GetAllByPriority<TModel>();
|
||||
}
|
||||
|
||||
public IReadOnlyList<TUtility> GetUtilitiesByPriority<TUtility>() where TUtility : class, IUtility
|
||||
{
|
||||
return _container.GetAllByPriority<TUtility>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送事件
|
||||
/// </summary>
|
||||
|
||||
249
GFramework.Core.Tests/architecture/PriorityServiceTests.cs
Normal file
249
GFramework.Core.Tests/architecture/PriorityServiceTests.cs
Normal file
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 优先级服务排序的集成测试
|
||||
/// 测试完整的架构集成场景
|
||||
/// </summary>
|
||||
[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!;
|
||||
|
||||
/// <summary>
|
||||
/// 测试系统按优先级排序
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Systems_Should_Be_Sorted_By_Priority()
|
||||
{
|
||||
// Arrange
|
||||
_container.Register<IPriorityTestSystem>(new PriorityTestSystemC());
|
||||
_container.Register<IPriorityTestSystem>(new PriorityTestSystemA());
|
||||
_container.Register<IPriorityTestSystem>(new PriorityTestSystemB());
|
||||
_container.Freeze();
|
||||
|
||||
// Act
|
||||
var systems = _container.GetAllByPriority<IPriorityTestSystem>();
|
||||
|
||||
// Assert
|
||||
Assert.That(systems, Has.Count.EqualTo(3));
|
||||
Assert.That(systems[0], Is.InstanceOf<PriorityTestSystemA>()); // Priority = 10
|
||||
Assert.That(systems[1], Is.InstanceOf<PriorityTestSystemB>()); // Priority = 20
|
||||
Assert.That(systems[2], Is.InstanceOf<PriorityTestSystemC>()); // Priority = 30
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试模型按优先级排序
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Models_Should_Be_Sorted_By_Priority()
|
||||
{
|
||||
// Arrange
|
||||
_container.Register<IPriorityTestModel>(new PriorityTestModelC());
|
||||
_container.Register<IPriorityTestModel>(new PriorityTestModelA());
|
||||
_container.Register<IPriorityTestModel>(new PriorityTestModelB());
|
||||
_container.Freeze();
|
||||
|
||||
// Act
|
||||
var models = _container.GetAllByPriority<IPriorityTestModel>();
|
||||
|
||||
// Assert
|
||||
Assert.That(models, Has.Count.EqualTo(3));
|
||||
Assert.That(models[0], Is.InstanceOf<PriorityTestModelA>()); // Priority = 10
|
||||
Assert.That(models[1], Is.InstanceOf<PriorityTestModelB>()); // Priority = 20
|
||||
Assert.That(models[2], Is.InstanceOf<PriorityTestModelC>()); // Priority = 30
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试工具按优先级排序
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Utilities_Should_Be_Sorted_By_Priority()
|
||||
{
|
||||
// Arrange
|
||||
_container.Register<IPriorityTestUtility>(new PriorityTestUtilityC());
|
||||
_container.Register<IPriorityTestUtility>(new PriorityTestUtilityA());
|
||||
_container.Register<IPriorityTestUtility>(new PriorityTestUtilityB());
|
||||
_container.Freeze();
|
||||
|
||||
// Act
|
||||
var utilities = _container.GetAllByPriority<IPriorityTestUtility>();
|
||||
|
||||
// Assert
|
||||
Assert.That(utilities, Has.Count.EqualTo(3));
|
||||
Assert.That(utilities[0], Is.InstanceOf<PriorityTestUtilityA>()); // Priority = 10
|
||||
Assert.That(utilities[1], Is.InstanceOf<PriorityTestUtilityB>()); // Priority = 20
|
||||
Assert.That(utilities[2], Is.InstanceOf<PriorityTestUtilityC>()); // Priority = 30
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试混合优先级和非优先级服务
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Mixed_Prioritized_And_Non_Prioritized_Should_Work()
|
||||
{
|
||||
// Arrange
|
||||
_container.Register<IMixedTestSystem>(new MixedTestSystemWithPriority());
|
||||
_container.Register<IMixedTestSystem>(new MixedTestSystemWithoutPriority());
|
||||
_container.Register<IMixedTestSystem>(new MixedTestSystemNegativePriority());
|
||||
_container.Freeze();
|
||||
|
||||
// Act
|
||||
var systems = _container.GetAllByPriority<IMixedTestSystem>();
|
||||
|
||||
// Assert
|
||||
Assert.That(systems, Has.Count.EqualTo(3));
|
||||
Assert.That(systems[0], Is.InstanceOf<MixedTestSystemNegativePriority>()); // -10
|
||||
Assert.That(systems[1], Is.InstanceOf<MixedTestSystemWithoutPriority>()); // 0 (默认)
|
||||
Assert.That(systems[2], Is.InstanceOf<MixedTestSystemWithPriority>()); // 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
|
||||
@ -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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试按优先级排序功能 - 升序排序
|
||||
/// </summary>
|
||||
[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<IPrioritizedService>(service1);
|
||||
_container.Register<IPrioritizedService>(service2);
|
||||
_container.Register<IPrioritizedService>(service3);
|
||||
_container.Freeze();
|
||||
|
||||
// Act
|
||||
var services = _container.GetAllByPriority<IPrioritizedService>();
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试未实现 IPrioritized 的服务使用默认优先级 0
|
||||
/// </summary>
|
||||
[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<IMixedService>(service1);
|
||||
_container.Register<IMixedService>(service2);
|
||||
_container.Register<IMixedService>(service3);
|
||||
_container.Freeze();
|
||||
|
||||
// Act
|
||||
var services = _container.GetAllByPriority<IMixedService>();
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试相同优先级保持注册顺序(稳定排序)
|
||||
/// </summary>
|
||||
[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<IPrioritizedService>(service1);
|
||||
_container.Register<IPrioritizedService>(service2);
|
||||
_container.Register<IPrioritizedService>(service3);
|
||||
_container.Freeze();
|
||||
|
||||
// Act
|
||||
var services = _container.GetAllByPriority<IPrioritizedService>();
|
||||
|
||||
// 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"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试空列表处理
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void GetAllByPriority_Should_Handle_Empty_List()
|
||||
{
|
||||
// Arrange
|
||||
_container.Freeze();
|
||||
|
||||
// Act
|
||||
var services = _container.GetAllByPriority<IPrioritizedService>();
|
||||
|
||||
// Assert
|
||||
Assert.That(services, Is.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试单项列表处理
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void GetAllByPriority_Should_Handle_Single_Item()
|
||||
{
|
||||
// Arrange
|
||||
var service = new PrioritizedService { Priority = 42 };
|
||||
_container.RegisterSingleton<IPrioritizedService>(service);
|
||||
_container.Freeze();
|
||||
|
||||
// Act
|
||||
var services = _container.GetAllByPriority<IPrioritizedService>();
|
||||
|
||||
// Assert
|
||||
Assert.That(services, Has.Count.EqualTo(1));
|
||||
Assert.That(services[0], Is.SameAs(service));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试负数优先级处理
|
||||
/// </summary>
|
||||
[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<IPrioritizedService>(service1);
|
||||
_container.Register<IPrioritizedService>(service2);
|
||||
_container.Register<IPrioritizedService>(service3);
|
||||
_container.Register<IPrioritizedService>(service4);
|
||||
_container.Freeze();
|
||||
|
||||
// Act
|
||||
var services = _container.GetAllByPriority<IPrioritizedService>();
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试混合优先级和非优先级服务
|
||||
/// </summary>
|
||||
[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<IMixedService>(service1);
|
||||
_container.Register<IMixedService>(service2);
|
||||
_container.Register<IMixedService>(service3);
|
||||
_container.Register<IMixedService>(service4);
|
||||
_container.Freeze();
|
||||
|
||||
// Act
|
||||
var services = _container.GetAllByPriority<IMixedService>();
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 GetAllByPriority(Type) 重载方法
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void GetAllByPriority_Type_Should_Sort_Correctly()
|
||||
{
|
||||
// Arrange
|
||||
var service1 = new PrioritizedService { Priority = 30 };
|
||||
var service2 = new PrioritizedService { Priority = 10 };
|
||||
|
||||
_container.Register<IPrioritizedService>(service1);
|
||||
_container.Register<IPrioritizedService>(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));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -449,4 +644,37 @@ public sealed class TestService : IService
|
||||
/// 获取或设置优先级
|
||||
/// </summary>
|
||||
public int Priority { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 优先级服务接口
|
||||
/// </summary>
|
||||
public interface IPrioritizedService : IPrioritized
|
||||
{
|
||||
string? Name { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 混合服务接口(用于测试优先级和非优先级混合)
|
||||
/// </summary>
|
||||
public interface IMixedService
|
||||
{
|
||||
string? Name { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实现优先级的服务
|
||||
/// </summary>
|
||||
public sealed class PrioritizedService : IPrioritizedService, IMixedService
|
||||
{
|
||||
public int Priority { get; set; }
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 不实现优先级的服务
|
||||
/// </summary>
|
||||
public sealed class NonPrioritizedService : IMixedService
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
@ -303,6 +303,50 @@ public class ArchitectureContext(IIocContainer container) : IArchitectureContext
|
||||
return _container.GetAll<TUtility>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有服务实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高)
|
||||
/// </summary>
|
||||
/// <typeparam name="TService">服务类型</typeparam>
|
||||
/// <returns>按优先级排序后的服务实例列表</returns>
|
||||
public IReadOnlyList<TService> GetServicesByPriority<TService>() where TService : class
|
||||
{
|
||||
return _container.GetAllByPriority<TService>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有系统实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的系统将按优先级排序(数值越小优先级越高)
|
||||
/// </summary>
|
||||
/// <typeparam name="TSystem">系统类型</typeparam>
|
||||
/// <returns>按优先级排序后的系统实例列表</returns>
|
||||
public IReadOnlyList<TSystem> GetSystemsByPriority<TSystem>() where TSystem : class, ISystem
|
||||
{
|
||||
return _container.GetAllByPriority<TSystem>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有模型实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的模型将按优先级排序(数值越小优先级越高)
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">模型类型</typeparam>
|
||||
/// <returns>按优先级排序后的模型实例列表</returns>
|
||||
public IReadOnlyList<TModel> GetModelsByPriority<TModel>() where TModel : class, IModel
|
||||
{
|
||||
return _container.GetAllByPriority<TModel>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有工具实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的工具将按优先级排序(数值越小优先级越高)
|
||||
/// </summary>
|
||||
/// <typeparam name="TUtility">工具类型</typeparam>
|
||||
/// <returns>按优先级排序后的工具实例列表</returns>
|
||||
public IReadOnlyList<TUtility> GetUtilitiesByPriority<TUtility>() where TUtility : class, IUtility
|
||||
{
|
||||
return _container.GetAllByPriority<TUtility>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Command Execution
|
||||
|
||||
@ -133,5 +133,65 @@ public static class ContextAwareServiceExtensions
|
||||
return context.GetUtilities<TUtility>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有服务实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高)
|
||||
/// </summary>
|
||||
/// <typeparam name="TService">服务类型</typeparam>
|
||||
/// <param name="contextAware">上下文感知对象</param>
|
||||
/// <returns>按优先级排序后的服务实例列表</returns>
|
||||
public static IReadOnlyList<TService> GetServicesByPriority<TService>(this IContextAware contextAware)
|
||||
where TService : class
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
var context = contextAware.GetContext();
|
||||
return context.GetServicesByPriority<TService>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有系统实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的系统将按优先级排序(数值越小优先级越高)
|
||||
/// </summary>
|
||||
/// <typeparam name="TSystem">系统类型</typeparam>
|
||||
/// <param name="contextAware">上下文感知对象</param>
|
||||
/// <returns>按优先级排序后的系统实例列表</returns>
|
||||
public static IReadOnlyList<TSystem> GetSystemsByPriority<TSystem>(this IContextAware contextAware)
|
||||
where TSystem : class, ISystem
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
var context = contextAware.GetContext();
|
||||
return context.GetSystemsByPriority<TSystem>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有模型实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的模型将按优先级排序(数值越小优先级越高)
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">模型类型</typeparam>
|
||||
/// <param name="contextAware">上下文感知对象</param>
|
||||
/// <returns>按优先级排序后的模型实例列表</returns>
|
||||
public static IReadOnlyList<TModel> GetModelsByPriority<TModel>(this IContextAware contextAware)
|
||||
where TModel : class, IModel
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
var context = contextAware.GetContext();
|
||||
return context.GetModelsByPriority<TModel>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有工具实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的工具将按优先级排序(数值越小优先级越高)
|
||||
/// </summary>
|
||||
/// <typeparam name="TUtility">工具类型</typeparam>
|
||||
/// <param name="contextAware">上下文感知对象</param>
|
||||
/// <returns>按优先级排序后的工具实例列表</returns>
|
||||
public static IReadOnlyList<TUtility> GetUtilitiesByPriority<TUtility>(this IContextAware contextAware)
|
||||
where TUtility : class, IUtility
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
var context = contextAware.GetContext();
|
||||
return context.GetUtilitiesByPriority<TUtility>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高)
|
||||
/// 未实现 IPrioritized 的服务将使用默认优先级 0
|
||||
/// </summary>
|
||||
/// <typeparam name="T">期望获取的实例类型</typeparam>
|
||||
/// <returns>按优先级排序后的实例列表</returns>
|
||||
public IReadOnlyList<T> GetAllByPriority<T>() where T : class
|
||||
{
|
||||
var services = GetAll<T>();
|
||||
return SortByPriority(services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的所有实例,并按优先级排序
|
||||
/// 实现 IPrioritized 接口的服务将按值越小优先级越高)
|
||||
/// 未实现 IPrioritized 的服务将使用默认优先级 0
|
||||
/// </summary>
|
||||
/// <param name="type">期望获取的实例类型</param>
|
||||
/// <returns>按优先级排序后的实例列表</returns>
|
||||
public IReadOnlyList<object> GetAllByPriority(Type type)
|
||||
{
|
||||
var services = GetAll(type);
|
||||
return SortByPriority(services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按优先级排序服务列表
|
||||
/// 实现 IPrioritized 接口的服务按 Priority 属性排序(升序)
|
||||
/// 未实现接口的服务使用默认优先级 0
|
||||
/// 相同优先级保持原有注册顺序(稳定排序)
|
||||
/// </summary>
|
||||
private static IReadOnlyList<T> SortByPriority<T>(IReadOnlyList<T> 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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user