feat(architecture): 添加架构初始化失败处理和阶段转换规则

- 将 CurrentPhase 属性改为公共读取私有设置
- 在 Initialize 和 InitializeAsync 方法中添加异常处理机制
- 添加 ArchitectureFailedInitializationEvent 事件类型
- 定义架构阶段转换规则,支持失败初始化状态转换
- 添加 FailedInitialization 枚举值
- 在同步测试架构中添加后注册钩子功能
- 重构测试基类,移除重复的测试方法
- 添加架构初始化失败时的错误日志记录
- 实现初始化失败时自动进入 FailedInitialization 阶段
This commit is contained in:
GwWuYou 2026-01-02 11:49:12 +08:00
parent 78da01878b
commit 3729e2ead2
7 changed files with 165 additions and 132 deletions

View File

@ -47,5 +47,10 @@ public enum ArchitecturePhase
/// <summary> /// <summary>
/// 已销毁 暂时不使用 /// 已销毁 暂时不使用
/// </summary> /// </summary>
Destroyed Destroyed,
/// <summary>
/// 初始化失败 暂时不使用
/// </summary>
FailedInitialization
} }

View File

@ -6,25 +6,55 @@ using GFramework.Core.Tests.system;
namespace GFramework.Core.Tests.architecture; namespace GFramework.Core.Tests.architecture;
/// <summary>
/// 同步测试架构类,用于测试架构的生命周期和事件处理
/// </summary>
public sealed class SyncTestArchitecture : Architecture public sealed class SyncTestArchitecture : Architecture
{ {
private Action<SyncTestArchitecture>? _postRegistrationHook;
/// <summary>
/// 获取就绪事件是否已触发的状态
/// </summary>
public bool ReadyEventFired { get; private set; } public bool ReadyEventFired { get; private set; }
/// <summary>
/// 获取初始化方法是否已调用的状态
/// </summary>
public bool InitCalled { get; private set; } public bool InitCalled { get; private set; }
public List<ArchitecturePhase> PhaseHistory { get; } = new(); /// <summary>
/// 获取架构阶段历史记录列表
/// </summary>
public List<ArchitecturePhase> PhaseHistory { get; } = [];
/// <summary>
/// 添加注册后钩子函数
/// </summary>
/// <param name="hook">要添加的钩子函数</param>
public void AddPostRegistrationHook(Action<SyncTestArchitecture> hook) => _postRegistrationHook = hook;
/// <summary>
/// 初始化架构组件,注册模型、系统并设置事件监听器
/// </summary>
protected override void Init() protected override void Init()
{ {
InitCalled = true; InitCalled = true;
RegisterModel(new TestModel()); RegisterModel(new TestModel());
RegisterSystem(new TestSystem()); RegisterSystem(new TestSystem());
_postRegistrationHook?.Invoke(this);
Context.RegisterEvent<ArchitectureEvents.ArchitectureLifecycleReadyEvent>(_ => { ReadyEventFired = true; }); Context.RegisterEvent<ArchitectureEvents.ArchitectureLifecycleReadyEvent>(_ => { ReadyEventFired = true; });
} }
/// <summary>
/// 进入指定架构阶段时的处理方法,记录阶段历史
/// </summary>
/// <param name="next">要进入的下一个架构阶段</param>
protected override void EnterPhase(ArchitecturePhase next) protected override void EnterPhase(ArchitecturePhase next)
{ {
base.EnterPhase(next); base.EnterPhase(next);
// 记录进入的架构阶段到历史列表中
PhaseHistory.Add(next); PhaseHistory.Add(next);
} }
} }

View File

@ -1,11 +1,5 @@
using System.Reflection; using GFramework.Core.architecture;
using GFramework.Core.Abstractions.enums;
using GFramework.Core.architecture;
using GFramework.Core.Tests.architecture;
using GFramework.Core.Tests.model;
using GFramework.Core.Tests.system;
using NUnit.Framework; using NUnit.Framework;
using NUnit.Framework.Legacy;
namespace GFramework.Core.Tests.tests; namespace GFramework.Core.Tests.tests;
@ -23,12 +17,6 @@ public abstract class ArchitectureTestsBase<TArchitecture> where TArchitecture :
/// <returns>创建的架构实例</returns> /// <returns>创建的架构实例</returns>
protected abstract TArchitecture CreateArchitecture(); protected abstract TArchitecture CreateArchitecture();
/// <summary>
/// 子类必须实现初始化架构(同步或异步)
/// </summary>
/// <returns>异步初始化任务</returns>
protected abstract Task InitializeArchitecture();
/// <summary> /// <summary>
/// 测试设置方法,在每个测试开始前执行 /// 测试设置方法,在每个测试开始前执行
/// 清理游戏上下文并创建架构实例 /// 清理游戏上下文并创建架构实例
@ -57,85 +45,4 @@ public abstract class ArchitectureTestsBase<TArchitecture> where TArchitecture :
Architecture = null; Architecture = null;
} }
} }
/// <summary>
/// 验证架构阶段顺序
/// </summary>
/// <returns>异步测试任务</returns>
[Test]
public async Task Architecture_Should_Enter_Phases_In_Correct_Order()
{
await InitializeArchitecture();
// 通过反射获取架构的阶段历史记录
var phasesProperty = typeof(TArchitecture)
.GetProperty("PhaseHistory", BindingFlags.Instance | BindingFlags.Public);
var phases = (List<ArchitecturePhase>)phasesProperty!.GetValue(Architecture)!;
CollectionAssert.AreEqual(
new[]
{
ArchitecturePhase.BeforeModelInit,
ArchitecturePhase.AfterModelInit,
ArchitecturePhase.BeforeSystemInit,
ArchitecturePhase.AfterSystemInit,
ArchitecturePhase.Ready
},
phases
);
}
/// <summary>
/// 验证 Ready 后不能注册组件
/// </summary>
/// <returns>异步测试任务</returns>
[Test]
public async Task Registering_Components_AfterReady_Should_Throw()
{
await InitializeArchitecture();
// 根据架构类型验证注册组件时抛出异常
if (Architecture is SyncTestArchitecture syncArch)
{
Assert.Throws<InvalidOperationException>(() => syncArch.RegisterModel(new TestModel()));
Assert.Throws<InvalidOperationException>(() => syncArch.RegisterSystem(new TestSystem()));
}
else if (Architecture is AsyncTestArchitecture asyncArch)
{
Assert.Throws<InvalidOperationException>(() => asyncArch.RegisterModel(new AsyncTestModel()));
Assert.Throws<InvalidOperationException>(() => asyncArch.RegisterSystem(new AsyncTestSystem()));
}
}
/// <summary>
/// 验证销毁功能
/// </summary>
/// <returns>异步测试任务</returns>
[Test]
public async Task Architecture_Destroy_Should_Destroy_All_Systems_And_Enter_Destroyed()
{
await InitializeArchitecture();
Architecture!.Destroy();
// 验证系统是否被正确销毁
if (Architecture is SyncTestArchitecture syncArch)
{
var system = syncArch.Context.GetSystem<TestSystem>();
Assert.That(system!.DestroyCalled, Is.True);
}
else if (Architecture is AsyncTestArchitecture asyncArch)
{
var system = asyncArch.Context.GetSystem<AsyncTestSystem>();
Assert.That(system!.DestroyCalled, Is.True);
}
// 通过反射验证当前阶段为销毁状态
var phaseProperty = typeof(TArchitecture)
.GetProperty("CurrentPhase", BindingFlags.Instance | BindingFlags.NonPublic);
var phase = (ArchitecturePhase)phaseProperty!.GetValue(Architecture)!;
Assert.That(phase, Is.EqualTo(ArchitecturePhase.Destroyed));
}
} }

View File

@ -1,38 +1,21 @@
using System.Reflection; using GFramework.Core.Abstractions.enums;
using GFramework.Core.Abstractions.enums;
using GFramework.Core.architecture; using GFramework.Core.architecture;
using GFramework.Core.Tests.architecture; using GFramework.Core.Tests.architecture;
using GFramework.Core.Tests.model; using GFramework.Core.Tests.model;
using GFramework.Core.Tests.system; using GFramework.Core.Tests.system;
using NUnit.Framework; using NUnit.Framework;
using NUnit.Framework.Legacy;
namespace GFramework.Core.Tests.tests; namespace GFramework.Core.Tests.tests;
/// <summary> /// <summary>
/// 同步架构测试类,用于测试同步架构的功能和行为 /// 同步架构测试类,用于测试同步架构的初始化、生命周期和组件注册等功能
/// </summary> /// </summary>
/// <remarks>
/// 该测试类使用非并行执行模式,确保测试的隔离性和可靠性
/// </remarks>
[TestFixture] [TestFixture]
[NonParallelizable] [NonParallelizable]
public class SyncArchitectureTests : ArchitectureTestsBase<SyncTestArchitecture> public class SyncArchitectureTests : ArchitectureTestsBase<SyncTestArchitecture>
{ {
/// <summary> protected override SyncTestArchitecture CreateArchitecture() => new();
/// 创建同步测试架构实例
/// </summary>
/// <returns>SyncTestArchitecture实例</returns>
protected override SyncTestArchitecture CreateArchitecture() => new SyncTestArchitecture();
/// <summary>
/// 初始化架构异步方法
/// </summary>
/// <returns>表示异步操作的Task</returns>
protected override Task InitializeArchitecture()
{
Architecture!.Initialize();
return Task.CompletedTask;
}
/// <summary> /// <summary>
/// 测试架构是否正确初始化所有组件 /// 测试架构是否正确初始化所有组件
@ -49,11 +32,7 @@ public class SyncArchitectureTests : ArchitectureTestsBase<SyncTestArchitecture>
Assert.That(Architecture.Runtime, Is.Not.Null); Assert.That(Architecture.Runtime, Is.Not.Null);
// 通过反射获取当前架构阶段 var phase = Architecture.CurrentPhase;
var phaseProperty = typeof(Architecture)
.GetProperty("CurrentPhase", BindingFlags.Instance | BindingFlags.NonPublic);
var phase = (ArchitecturePhase)phaseProperty!.GetValue(Architecture)!;
Assert.That(phase, Is.EqualTo(ArchitecturePhase.Ready)); Assert.That(phase, Is.EqualTo(ArchitecturePhase.Ready));
var context = Architecture.Context; var context = Architecture.Context;
@ -80,14 +59,77 @@ public class SyncArchitectureTests : ArchitectureTestsBase<SyncTestArchitecture>
Assert.That(ctx, Is.Not.Null); Assert.That(ctx, Is.Not.Null);
} }
/// <summary>
/// 测试架构是否按正确顺序进入各个阶段
/// 验证架构初始化过程中各阶段的执行顺序
/// </summary>
[Test]
public void Architecture_Should_Enter_Phases_In_Correct_Order()
{
Architecture!.Initialize();
var phases = Architecture.PhaseHistory;
CollectionAssert.AreEqual(
new[]
{
ArchitecturePhase.BeforeModelInit,
ArchitecturePhase.AfterModelInit,
ArchitecturePhase.BeforeSystemInit,
ArchitecturePhase.AfterSystemInit,
ArchitecturePhase.Ready
},
phases
);
}
/// <summary>
/// 测试在架构就绪后注册系统是否抛出异常(当不允许时)
/// </summary>
[Test]
public void RegisterSystem_AfterReady_Should_Throw_When_NotAllowed()
{
Architecture!.Initialize();
Assert.Throws<InvalidOperationException>(() => { Architecture.RegisterSystem(new TestSystem()); });
}
/// <summary>
/// 测试在架构就绪后注册模型是否抛出异常(当不允许时)
/// </summary>
[Test]
public void RegisterModel_AfterReady_Should_Throw_When_NotAllowed()
{
Architecture!.Initialize();
Assert.Throws<InvalidOperationException>(() => { Architecture.RegisterModel(new TestModel()); });
}
/// <summary>
/// 测试架构销毁功能,验证销毁后系统被正确销毁且架构进入销毁阶段
/// </summary>
[Test]
public void Architecture_Destroy_Should_Destroy_All_Systems_And_Enter_Destroyed()
{
Architecture!.Initialize();
Architecture.Destroy();
var system = Architecture.Context.GetSystem<TestSystem>();
Assert.That(system!.DestroyCalled, Is.True);
var phase = Architecture.CurrentPhase;
Assert.That(phase, Is.EqualTo(ArchitecturePhase.Destroyed));
}
/// <summary> /// <summary>
/// 测试当模型初始化失败时架构是否停止初始化 /// 测试当模型初始化失败时架构是否停止初始化
/// </summary> /// </summary>
[Test] [Test]
public void Architecture_Should_Stop_Initialization_When_Model_Init_Fails() public void Architecture_Should_Stop_Initialization_When_Model_Init_Fails()
{ {
Architecture!.RegisterModel(new FailingModel()); Architecture!.AddPostRegistrationHook(architecture => { architecture.RegisterModel(new FailingModel()); });
// 调用初始化
Assert.Throws<InvalidOperationException>(() => { Architecture!.Initialize(); }); Architecture.Initialize();
Assert.That(Architecture.CurrentPhase, Is.EqualTo(ArchitecturePhase.FailedInitialization));
} }
} }

View File

@ -112,7 +112,7 @@ public abstract class Architecture(
/// <summary> /// <summary>
/// 当前架构的阶段 /// 当前架构的阶段
/// </summary> /// </summary>
private ArchitecturePhase CurrentPhase { get; set; } public ArchitecturePhase CurrentPhase { get; private set; }
/// <summary> /// <summary>
/// 日志记录器实例,用于记录应用程序的运行日志 /// 日志记录器实例,用于记录应用程序的运行日志
@ -236,7 +236,17 @@ public abstract class Architecture(
/// </summary> /// </summary>
public void Initialize() public void Initialize()
{ {
InitializeInternalAsync(asyncMode: false).GetAwaiter().GetResult(); try
{
InitializeInternalAsync(asyncMode: false).GetAwaiter().GetResult();
}
catch (Exception e)
{
_logger.Error("Architecture initialization failed:", e);
EnterPhase(ArchitecturePhase.FailedInitialization);
// 发送初始化失败事件
TypeEventSystem.Send(new ArchitectureEvents.ArchitectureFailedInitializationEvent());
}
} }
/// <summary> /// <summary>
@ -245,7 +255,18 @@ public abstract class Architecture(
/// <returns>表示异步初始化操作的Task</returns> /// <returns>表示异步初始化操作的Task</returns>
public Task InitializeAsync() public Task InitializeAsync()
{ {
return InitializeInternalAsync(asyncMode: true); try
{
return InitializeInternalAsync(asyncMode: true);
}
catch (Exception e)
{
_logger.Error("Architecture initialization failed:", e);
EnterPhase(ArchitecturePhase.FailedInitialization);
// 发送初始化失败事件
TypeEventSystem.Send(new ArchitectureEvents.ArchitectureFailedInitializationEvent());
return Task.CompletedTask;
}
} }
/// <summary> /// <summary>

View File

@ -3,17 +3,39 @@ using GFramework.Core.Abstractions.enums;
namespace GFramework.Core.architecture; namespace GFramework.Core.architecture;
/// <summary>
/// 架构常量类,定义了架构阶段转换规则
/// </summary>
public static class ArchitectureConstants public static class ArchitectureConstants
{ {
/// <summary>
/// 定义架构阶段之间的有效转换关系
/// </summary>
/// <remarks>
/// 键为当前架构阶段,值为从该阶段可以转换到的下一阶段数组
/// </remarks>
public static readonly ImmutableDictionary<ArchitecturePhase, ArchitecturePhase[]> PhaseTransitions = public static readonly ImmutableDictionary<ArchitecturePhase, ArchitecturePhase[]> PhaseTransitions =
new Dictionary<ArchitecturePhase, ArchitecturePhase[]> new Dictionary<ArchitecturePhase, ArchitecturePhase[]>
{ {
{ ArchitecturePhase.None, [ArchitecturePhase.BeforeModelInit] }, { ArchitecturePhase.None, [ArchitecturePhase.BeforeModelInit] },
{ ArchitecturePhase.BeforeModelInit, [ArchitecturePhase.AfterModelInit] }, {
{ ArchitecturePhase.AfterModelInit, [ArchitecturePhase.BeforeSystemInit] }, ArchitecturePhase.BeforeModelInit, [
{ ArchitecturePhase.BeforeSystemInit, [ArchitecturePhase.AfterSystemInit] }, ArchitecturePhase.AfterModelInit, ArchitecturePhase.FailedInitialization
{ ArchitecturePhase.AfterSystemInit, [ArchitecturePhase.Ready] }, ]
},
{
ArchitecturePhase.AfterModelInit, [
ArchitecturePhase.BeforeSystemInit, ArchitecturePhase.FailedInitialization
]
},
{
ArchitecturePhase.BeforeSystemInit, [
ArchitecturePhase.AfterSystemInit, ArchitecturePhase.FailedInitialization
]
},
{ ArchitecturePhase.AfterSystemInit, [ArchitecturePhase.Ready, ArchitecturePhase.FailedInitialization] },
{ ArchitecturePhase.Ready, [ArchitecturePhase.Destroying] }, { ArchitecturePhase.Ready, [ArchitecturePhase.Destroying] },
{ ArchitecturePhase.FailedInitialization, [ArchitecturePhase.Destroying] },
{ ArchitecturePhase.Destroying, [ArchitecturePhase.Destroyed] } { ArchitecturePhase.Destroying, [ArchitecturePhase.Destroyed] }
}.ToImmutableDictionary(); }.ToImmutableDictionary();
} }

View File

@ -22,4 +22,10 @@ public static class ArchitectureEvents
/// 当架构完全销毁完成后触发此事件,表示系统已关闭 /// 当架构完全销毁完成后触发此事件,表示系统已关闭
/// </summary> /// </summary>
public readonly struct ArchitectureDestroyedEvent; public readonly struct ArchitectureDestroyedEvent;
/// <summary>
/// 架构初始化失败事件
/// 当架构初始化过程中发生错误时触发此事件
/// </summary>
public readonly struct ArchitectureFailedInitializationEvent;
} }