refactor(core): 重构上下文感知服务扩展以改进组件获取逻辑

- 引入通用的 GetRequiredComponent 方法来统一服务、系统、模型和工具的获取逻辑
- 添加对架构上下文组件的空值检查和异常处理
- 实现更清晰的错误消息以指示未注册的组件类型
- 为所有组件类型(服务、系统、模型、工具)添加缺失的单元测试
- 测试验证当上下文返回空组件时抛出正确的 InvalidOperationException
- 改进代码可维护性并减少重复的获取组件逻辑
This commit is contained in:
GeWuYou 2026-03-28 13:03:56 +08:00
parent 796408539e
commit b5ac8b2c34
2 changed files with 73 additions and 9 deletions

View File

@ -5,9 +5,9 @@ using GFramework.Core.Abstractions.Rule;
using GFramework.Core.Abstractions.Systems;
using GFramework.Core.Abstractions.Utility;
using GFramework.Core.Architectures;
using GFramework.Core.Extensions;
using GFramework.Core.Ioc;
using GFramework.Core.Rule;
using GFramework.Core.Tests.Architectures;
namespace GFramework.Core.Tests.Rule;
@ -18,6 +18,11 @@ namespace GFramework.Core.Tests.Rule;
[TestFixture]
public class ContextAwareServiceExtensionsTests
{
private MicrosoftDiContainer _container = null!;
private ArchitectureContext _context = null!;
private TestContextAware _contextAware = null!;
[SetUp]
public void SetUp()
{
@ -34,10 +39,6 @@ public class ContextAwareServiceExtensionsTests
_container.Clear();
}
private TestContextAware _contextAware = null!;
private ArchitectureContext _context = null!;
private MicrosoftDiContainer _container = null!;
[Test]
public void GetService_Should_Return_Registered_Service()
{
@ -53,6 +54,18 @@ public class ContextAwareServiceExtensionsTests
Assert.That(result, Is.SameAs(service));
}
[Test]
public void GetService_Should_Throw_When_Context_Returns_Null_Service()
{
// Arrange
var contextAware = new TestContextAware();
((IContextAware)contextAware).SetContext(new TestArchitectureContextV3());
// Act / Assert
Assert.That(() => contextAware.GetService<TestService>(),
Throws.InvalidOperationException.With.Message.Contains("Service"));
}
[Test]
public void GetSystem_Should_Return_Registered_System()
{
@ -68,6 +81,18 @@ public class ContextAwareServiceExtensionsTests
Assert.That(result, Is.SameAs(system));
}
[Test]
public void GetSystem_Should_Throw_When_Context_Returns_Null_System()
{
// Arrange
var contextAware = new TestContextAware();
((IContextAware)contextAware).SetContext(new TestArchitectureContextV3());
// Act / Assert
Assert.That(() => contextAware.GetSystem<TestSystem>(),
Throws.InvalidOperationException.With.Message.Contains("System"));
}
[Test]
public void GetModel_Should_Return_Registered_Model()
{
@ -83,6 +108,18 @@ public class ContextAwareServiceExtensionsTests
Assert.That(result, Is.SameAs(model));
}
[Test]
public void GetModel_Should_Throw_When_Context_Returns_Null_Model()
{
// Arrange
var contextAware = new TestContextAware();
((IContextAware)contextAware).SetContext(new TestArchitectureContextV3());
// Act / Assert
Assert.That(() => contextAware.GetModel<TestModel>(),
Throws.InvalidOperationException.With.Message.Contains("Model"));
}
[Test]
public void GetUtility_Should_Return_Registered_Utility()
{
@ -98,6 +135,18 @@ public class ContextAwareServiceExtensionsTests
Assert.That(result, Is.SameAs(utility));
}
[Test]
public void GetUtility_Should_Throw_When_Context_Returns_Null_Utility()
{
// Arrange
var contextAware = new TestContextAware();
((IContextAware)contextAware).SetContext(new TestArchitectureContextV3());
// Act / Assert
Assert.That(() => contextAware.GetUtility<TestUtility>(),
Throws.InvalidOperationException.With.Message.Contains("Utility"));
}
[Test]
public void GetServices_Should_Return_All_Registered_Services()
{

View File

@ -1,3 +1,4 @@
using GFramework.Core.Abstractions.Architectures;
using GFramework.Core.Abstractions.Model;
using GFramework.Core.Abstractions.Rule;
using GFramework.Core.Abstractions.Systems;
@ -25,7 +26,8 @@ public static class ContextAwareServiceExtensions
{
ArgumentNullException.ThrowIfNull(contextAware);
var context = contextAware.GetContext();
return context.GetService<TService>();
return GetRequiredComponent(context, static architectureContext => architectureContext.GetService<TService>(),
"Service");
}
/// <summary>
@ -39,7 +41,8 @@ public static class ContextAwareServiceExtensions
{
ArgumentNullException.ThrowIfNull(contextAware);
var context = contextAware.GetContext();
return context.GetSystem<TSystem>();
return GetRequiredComponent(context, static architectureContext => architectureContext.GetSystem<TSystem>(),
"System");
}
/// <summary>
@ -53,7 +56,8 @@ public static class ContextAwareServiceExtensions
{
ArgumentNullException.ThrowIfNull(contextAware);
var context = contextAware.GetContext();
return context.GetModel<TModel>();
return GetRequiredComponent(context, static architectureContext => architectureContext.GetModel<TModel>(),
"Model");
}
/// <summary>
@ -67,7 +71,8 @@ public static class ContextAwareServiceExtensions
{
ArgumentNullException.ThrowIfNull(contextAware);
var context = contextAware.GetContext();
return context.GetUtility<TUtility>();
return GetRequiredComponent(context, static architectureContext => architectureContext.GetUtility<TUtility>(),
"Utility");
}
#endregion
@ -194,5 +199,15 @@ public static class ContextAwareServiceExtensions
return context.GetUtilitiesByPriority<TUtility>();
}
private static TComponent GetRequiredComponent<TComponent>(IArchitectureContext context,
Func<IArchitectureContext, TComponent> resolver, string componentKind)
where TComponent : class
{
ArgumentNullException.ThrowIfNull(context);
var component = resolver(context);
return component ?? throw new InvalidOperationException($"{componentKind} {typeof(TComponent)} not registered");
}
#endregion
}