- 将所有小写的命名空间导入更正为首字母大写格式 - 统一 GFramework 框架的命名空间引用规范 - 修复 core、ecs、godot 等模块的命名空间导入错误 - 标准化文档示例代码中的 using 语句格式 - 确保所有文档中的命名空间引用保持一致性 - 更新 global using 语句以匹配正确的命名空间格式
11 KiB
title, description
| title | description |
|---|---|
| 生命周期管理 | 生命周期管理提供了标准化的组件初始化和销毁机制,确保资源的正确管理和释放。 |
生命周期管理
概述
生命周期管理是 GFramework 中用于管理组件初始化和销毁的核心机制。通过实现标准的生命周期接口,组件可以在适当的时机执行初始化逻辑和资源清理,确保系统的稳定性和资源的有效管理。
GFramework 提供了同步和异步两套生命周期接口,适用于不同的使用场景。架构会自动管理所有注册组件的生命周期,开发者只需实现相应的接口即可。
主要特性:
- 标准化的初始化和销毁流程
- 支持同步和异步操作
- 自动生命周期管理
- 按注册顺序初始化,按逆序销毁
- 与架构系统深度集成
核心概念
生命周期接口层次
GFramework 提供了一套完整的生命周期接口:
// 同步接口
public interface IInitializable
{
void Initialize();
}
public interface IDestroyable
{
void Destroy();
}
public interface ILifecycle : IInitializable, IDestroyable
{
}
// 异步接口
public interface IAsyncInitializable
{
Task InitializeAsync();
}
public interface IAsyncDestroyable
{
ValueTask DestroyAsync();
}
public interface IAsyncLifecycle : IAsyncInitializable, IAsyncDestroyable
{
}
初始化阶段
组件在注册到架构后会自动进行初始化:
public class PlayerModel : AbstractModel
{
protected override void OnInit()
{
// 初始化逻辑
Console.WriteLine("PlayerModel 初始化");
}
}
销毁阶段
当架构销毁时,所有实现了 IDestroyable 的组件会按注册的逆序被销毁:
public class GameSystem : AbstractSystem
{
public void Destroy()
{
// 清理资源
Console.WriteLine("GameSystem 销毁");
}
}
基本用法
实现同步生命周期
最常见的方式是继承框架提供的抽象基类:
using GFramework.Core.Model;
public class InventoryModel : AbstractModel
{
private List<Item> _items = new();
protected override void OnInit()
{
// 初始化库存
_items = new List<Item>();
Console.WriteLine("库存系统已初始化");
}
}
实现销毁逻辑
对于需要清理资源的组件,实现 IDestroyable 接口:
using GFramework.Core.Abstractions.System;
using GFramework.Core.Abstractions.Lifecycle;
public class AudioSystem : ISystem, IDestroyable
{
private AudioEngine _engine;
public void Initialize()
{
_engine = new AudioEngine();
_engine.Start();
}
public void Destroy()
{
// 清理音频资源
_engine?.Stop();
_engine?.Dispose();
_engine = null;
}
}
在架构中注册
组件注册后,架构会自动管理其生命周期:
public class GameArchitecture : Architecture
{
protected override void Init()
{
// 注册顺序:Model -> System -> Utility
RegisterModel(new PlayerModel()); // 1. 初始化
RegisterModel(new InventoryModel()); // 2. 初始化
RegisterSystem(new AudioSystem()); // 3. 初始化
// 销毁顺序会自动反转:
// AudioSystem -> InventoryModel -> PlayerModel
}
}
高级用法
异步初始化
对于需要异步操作的组件(如加载配置、连接数据库),使用异步生命周期:
using GFramework.Core.Abstractions.Lifecycle;
using GFramework.Core.Abstractions.System;
public class ConfigurationSystem : ISystem, IAsyncInitializable
{
private Configuration _config;
public async Task InitializeAsync()
{
// 异步加载配置文件
_config = await LoadConfigurationAsync();
Console.WriteLine("配置已加载");
}
private async Task<Configuration> LoadConfigurationAsync()
{
await Task.Delay(100); // 模拟异步操作
return new Configuration();
}
}
异步销毁
对于需要异步清理的资源(如关闭网络连接、保存数据):
using GFramework.Core.Abstractions.Lifecycle;
public class NetworkSystem : ISystem, IAsyncDestroyable
{
private NetworkClient _client;
public void Initialize()
{
_client = new NetworkClient();
}
public async ValueTask DestroyAsync()
{
// 异步关闭连接
if (_client != null)
{
await _client.DisconnectAsync();
await _client.DisposeAsync();
}
Console.WriteLine("网络连接已关闭");
}
}
完整异步生命周期
同时实现异步初始化和销毁:
public class DatabaseSystem : ISystem, IAsyncLifecycle
{
private DatabaseConnection _connection;
public async Task InitializeAsync()
{
// 异步连接数据库
_connection = new DatabaseConnection();
await _connection.ConnectAsync("connection-string");
Console.WriteLine("数据库已连接");
}
public async ValueTask DestroyAsync()
{
// 异步关闭数据库连接
if (_connection != null)
{
await _connection.CloseAsync();
await _connection.DisposeAsync();
}
Console.WriteLine("数据库连接已关闭");
}
}
生命周期钩子
监听架构的生命周期阶段:
using GFramework.Core.Abstractions.Enums;
public class AnalyticsSystem : AbstractSystem
{
protected override void OnInit()
{
Console.WriteLine("分析系统初始化");
}
public override void OnArchitecturePhase(ArchitecturePhase phase)
{
switch (phase)
{
case ArchitecturePhase.Initializing:
Console.WriteLine("架构正在初始化");
break;
case ArchitecturePhase.Ready:
Console.WriteLine("架构已就绪");
StartTracking();
break;
case ArchitecturePhase.Destroying:
Console.WriteLine("架构正在销毁");
StopTracking();
break;
}
}
private void StartTracking() { }
private void StopTracking() { }
}
最佳实践
-
优先使用抽象基类:继承
AbstractModel、AbstractSystem等基类,它们已经实现了生命周期接口✓ public class MyModel : AbstractModel { } ✗ public class MyModel : IModel, IInitializable { } -
初始化顺序很重要:按依赖关系注册组件,被依赖的组件先注册
protected override void Init() { RegisterModel(new ConfigModel()); // 先注册配置 RegisterModel(new PlayerModel()); // 再注册依赖配置的模型 RegisterSystem(new GameplaySystem()); // 最后注册系统 } -
销毁时释放资源:实现
Destroy()方法清理非托管资源public void Destroy() { // 释放事件订阅 _eventBus.Unsubscribe<GameEvent>(OnGameEvent); // 释放非托管资源 _nativeHandle?.Dispose(); // 清空引用 _cache?.Clear(); } -
异步操作使用异步接口:避免在同步方法中阻塞异步操作
✓ public async Task InitializeAsync() { await LoadDataAsync(); } ✗ public void Initialize() { LoadDataAsync().Wait(); } // 可能死锁 -
避免在初始化中访问其他组件:初始化顺序可能导致组件尚未就绪
✗ protected override void OnInit() { var system = this.GetSystem<OtherSystem>(); // 可能尚未初始化 } ✓ public override void OnArchitecturePhase(ArchitecturePhase phase) { if (phase == ArchitecturePhase.Ready) { var system = this.GetSystem<OtherSystem>(); // 安全 } } -
使用 OnArchitecturePhase 处理跨组件依赖:在 Ready 阶段访问其他组件
public override void OnArchitecturePhase(ArchitecturePhase phase) { if (phase == ArchitecturePhase.Ready) { // 此时所有组件都已初始化完成 var config = this.GetModel<ConfigModel>(); ApplyConfiguration(config); } }
常见问题
问题:什么时候使用同步 vs 异步生命周期?
解答:
- 同步:简单的初始化逻辑,如创建对象、设置默认值
- 异步:需要 I/O 操作的场景,如加载文件、网络请求、数据库连接
// 同步:简单初始化
public class ScoreModel : AbstractModel
{
protected override void OnInit()
{
Score = 0; // 简单赋值
}
}
// 异步:需要 I/O
public class SaveSystem : ISystem, IAsyncInitializable
{
public async Task InitializeAsync()
{
await LoadSaveDataAsync(); // 文件 I/O
}
}
问题:组件的初始化和销毁顺序是什么?
解答:
- 初始化顺序:按注册顺序(先注册先初始化)
- 销毁顺序:按注册的逆序(后注册先销毁)
protected override void Init()
{
RegisterModel(new A()); // 1. 初始化,3. 销毁
RegisterModel(new B()); // 2. 初始化,2. 销毁
RegisterSystem(new C()); // 3. 初始化,1. 销毁
}
问题:如何在初始化时访问其他组件?
解答:
不要在 OnInit() 中访问其他组件,使用 OnArchitecturePhase() 在 Ready 阶段访问:
public class DependentSystem : AbstractSystem
{
protected override void OnInit()
{
// ✗ 不要在这里访问其他组件
}
public override void OnArchitecturePhase(ArchitecturePhase phase)
{
if (phase == ArchitecturePhase.Ready)
{
// ✓ 在这里安全访问其他组件
var config = this.GetModel<ConfigModel>();
}
}
}
问题:Destroy() 方法一定会被调用吗?
解答:
只有在正常销毁架构时才会调用。如果应用程序崩溃或被强制终止,Destroy() 可能不会被调用。因此:
- 不要依赖
Destroy()保存关键数据 - 使用自动保存机制保护重要数据
- 非托管资源应该实现
IDisposable模式
问题:可以在 Destroy() 中访问其他组件吗?
解答: 不推荐。销毁时其他组件可能已经被销毁。如果必须访问,确保检查组件是否仍然可用:
public void Destroy()
{
// ✗ 不安全
var system = this.GetSystem<OtherSystem>();
system.DoSomething();
// ✓ 安全
try
{
var system = this.GetSystem<OtherSystem>();
system?.DoSomething();
}
catch
{
// 组件可能已销毁
}
}