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.Systems;
using GFramework.Core.Abstractions.Utility; using GFramework.Core.Abstractions.Utility;
using GFramework.Core.Architectures; using GFramework.Core.Architectures;
using GFramework.Core.Extensions;
using GFramework.Core.Ioc; using GFramework.Core.Ioc;
using GFramework.Core.Rule; using GFramework.Core.Rule;
using GFramework.Core.Tests.Architectures;
namespace GFramework.Core.Tests.Rule; namespace GFramework.Core.Tests.Rule;
@ -18,6 +18,11 @@ namespace GFramework.Core.Tests.Rule;
[TestFixture] [TestFixture]
public class ContextAwareServiceExtensionsTests public class ContextAwareServiceExtensionsTests
{ {
private MicrosoftDiContainer _container = null!;
private ArchitectureContext _context = null!;
private TestContextAware _contextAware = null!;
[SetUp] [SetUp]
public void SetUp() public void SetUp()
{ {
@ -34,10 +39,6 @@ public class ContextAwareServiceExtensionsTests
_container.Clear(); _container.Clear();
} }
private TestContextAware _contextAware = null!;
private ArchitectureContext _context = null!;
private MicrosoftDiContainer _container = null!;
[Test] [Test]
public void GetService_Should_Return_Registered_Service() public void GetService_Should_Return_Registered_Service()
{ {
@ -53,6 +54,18 @@ public class ContextAwareServiceExtensionsTests
Assert.That(result, Is.SameAs(service)); 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] [Test]
public void GetSystem_Should_Return_Registered_System() public void GetSystem_Should_Return_Registered_System()
{ {
@ -68,6 +81,18 @@ public class ContextAwareServiceExtensionsTests
Assert.That(result, Is.SameAs(system)); 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] [Test]
public void GetModel_Should_Return_Registered_Model() public void GetModel_Should_Return_Registered_Model()
{ {
@ -83,6 +108,18 @@ public class ContextAwareServiceExtensionsTests
Assert.That(result, Is.SameAs(model)); 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] [Test]
public void GetUtility_Should_Return_Registered_Utility() public void GetUtility_Should_Return_Registered_Utility()
{ {
@ -98,6 +135,18 @@ public class ContextAwareServiceExtensionsTests
Assert.That(result, Is.SameAs(utility)); 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] [Test]
public void GetServices_Should_Return_All_Registered_Services() 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.Model;
using GFramework.Core.Abstractions.Rule; using GFramework.Core.Abstractions.Rule;
using GFramework.Core.Abstractions.Systems; using GFramework.Core.Abstractions.Systems;
@ -25,7 +26,8 @@ public static class ContextAwareServiceExtensions
{ {
ArgumentNullException.ThrowIfNull(contextAware); ArgumentNullException.ThrowIfNull(contextAware);
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetService<TService>(); return GetRequiredComponent(context, static architectureContext => architectureContext.GetService<TService>(),
"Service");
} }
/// <summary> /// <summary>
@ -39,7 +41,8 @@ public static class ContextAwareServiceExtensions
{ {
ArgumentNullException.ThrowIfNull(contextAware); ArgumentNullException.ThrowIfNull(contextAware);
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetSystem<TSystem>(); return GetRequiredComponent(context, static architectureContext => architectureContext.GetSystem<TSystem>(),
"System");
} }
/// <summary> /// <summary>
@ -53,7 +56,8 @@ public static class ContextAwareServiceExtensions
{ {
ArgumentNullException.ThrowIfNull(contextAware); ArgumentNullException.ThrowIfNull(contextAware);
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetModel<TModel>(); return GetRequiredComponent(context, static architectureContext => architectureContext.GetModel<TModel>(),
"Model");
} }
/// <summary> /// <summary>
@ -67,7 +71,8 @@ public static class ContextAwareServiceExtensions
{ {
ArgumentNullException.ThrowIfNull(contextAware); ArgumentNullException.ThrowIfNull(contextAware);
var context = contextAware.GetContext(); var context = contextAware.GetContext();
return context.GetUtility<TUtility>(); return GetRequiredComponent(context, static architectureContext => architectureContext.GetUtility<TUtility>(),
"Utility");
} }
#endregion #endregion
@ -194,5 +199,15 @@ public static class ContextAwareServiceExtensions
return context.GetUtilitiesByPriority<TUtility>(); 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 #endregion
} }