From 11c94d462f9bfb4a0b4adebfbcfead9e8394c7a6 Mon Sep 17 00:00:00 2001
From: GeWuYou <95328647+GeWuYou@users.noreply.github.com>
Date: Tue, 27 Jan 2026 22:22:20 +0800
Subject: [PATCH] =?UTF-8?q?feat(setting):=20=E6=B7=BB=E5=8A=A0=E8=AE=BE?=
=?UTF-8?q?=E7=BD=AE=E6=95=B0=E6=8D=AE=E7=89=88=E6=9C=AC=E8=BF=81=E7=A7=BB?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 IVersioned 接口用于定义版本信息
- 实现设置数据自动迁移机制,支持版本升级转换
- 添加 SettingsMigration 接口用于处理不同版本间的数据转换
- 在 SettingsModel 中集成迁移功能,加载时自动执行版本迁移
- 优化设置数据管理,新增 AllData 方法获取所有设置数据
- 重构代码结构,添加清晰的方法分组注释块
---
.../versioning/IVersioned.cs | 25 ++++
.../setting/ISettingsMigration.cs | 42 ++++++
GFramework.Game/setting/SettingsModel.cs | 138 ++++++++++++------
3 files changed, 160 insertions(+), 45 deletions(-)
create mode 100644 GFramework.Core.Abstractions/versioning/IVersioned.cs
create mode 100644 GFramework.Game.Abstractions/setting/ISettingsMigration.cs
diff --git a/GFramework.Core.Abstractions/versioning/IVersioned.cs b/GFramework.Core.Abstractions/versioning/IVersioned.cs
new file mode 100644
index 0000000..ea39d70
--- /dev/null
+++ b/GFramework.Core.Abstractions/versioning/IVersioned.cs
@@ -0,0 +1,25 @@
+// Copyright (c) 2026 GeWuYou
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace GFramework.Core.Abstractions.versioning;
+
+///
+/// 定义具有版本信息的接口
+///
+public interface IVersioned
+{
+ ///
+ /// 获取对象的版本号
+ ///
+ int Version { get; }
+}
\ No newline at end of file
diff --git a/GFramework.Game.Abstractions/setting/ISettingsMigration.cs b/GFramework.Game.Abstractions/setting/ISettingsMigration.cs
new file mode 100644
index 0000000..ee8388c
--- /dev/null
+++ b/GFramework.Game.Abstractions/setting/ISettingsMigration.cs
@@ -0,0 +1,42 @@
+// Copyright (c) 2026 GeWuYou
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace GFramework.Game.Abstractions.setting;
+
+///
+/// 定义设置数据迁移接口,用于处理不同版本设置数据之间的转换
+///
+public interface ISettingsMigration
+{
+ ///
+ /// 获取要迁移的设置类型
+ ///
+ Type SettingsType { get; }
+
+ ///
+ /// 获取源版本号(迁移前的版本)
+ ///
+ int FromVersion { get; }
+
+ ///
+ /// 获取目标版本号(迁移后的版本)
+ ///
+ int ToVersion { get; }
+
+ ///
+ /// 执行设置数据迁移操作
+ ///
+ /// 需要迁移的旧版设置数据
+ /// 迁移后的新版设置数据
+ ISettingsSection Migrate(ISettingsSection oldData);
+}
\ No newline at end of file
diff --git a/GFramework.Game/setting/SettingsModel.cs b/GFramework.Game/setting/SettingsModel.cs
index 6608f89..4f9f7f3 100644
--- a/GFramework.Game/setting/SettingsModel.cs
+++ b/GFramework.Game/setting/SettingsModel.cs
@@ -1,4 +1,5 @@
-using GFramework.Core.extensions;
+using GFramework.Core.Abstractions.versioning;
+using GFramework.Core.extensions;
using GFramework.Core.model;
using GFramework.Game.Abstractions.setting;
@@ -11,87 +12,91 @@ public class SettingsModel : AbstractModel, ISettingsModel
{
private readonly Dictionary _applicators = new();
private readonly Dictionary _dataSettings = new();
+ private readonly Dictionary<(Type type, int from), ISettingsMigration> _migrations = new();
+
private ISettingsPersistence? _persistence;
+ // -----------------------------
+ // Data
+ // -----------------------------
+
///
- /// 获取或创建数据设置
+ /// 获取指定类型的设置数据实例,如果不存在则创建新的实例
///
- /// 设置数据类型,必须实现ISettingsData接口并具有无参构造函数
+ /// 设置数据类型,必须实现ISettingsData接口并提供无参构造函数
/// 指定类型的设置数据实例
public T GetData() where T : class, ISettingsData, new()
{
var type = typeof(T);
+ if (_dataSettings.TryGetValue(type, out var data))
+ return (T)data;
- // 尝试从现有字典中获取已存在的设置数据
- if (_dataSettings.TryGetValue(type, out var existing))
- return (T)existing;
-
- // 创建新的设置数据实例并存储到字典中
var created = new T();
_dataSettings[type] = created;
return created;
}
///
- /// 获取所有已注册的可应用设置
+ /// 获取所有设置数据的枚举集合
///
- /// 所有可应用设置的枚举集合
- public IEnumerable AllApplicators()
- {
- return _applicators.Values;
- }
+ /// 所有设置数据的枚举集合
+ public IEnumerable AllData()
+ => _dataSettings.Values;
+
+ // -----------------------------
+ // Applicator
+ // -----------------------------
///
- /// 注册可应用设置(必须手动注册)
+ /// 获取所有设置应用器的枚举集合
///
- /// 可应用设置的类型,必须继承自class和IApplyAbleSettings
- /// 要注册的可应用设置实例
- /// 返回当前设置模型实例,支持链式调用
- public ISettingsModel RegisterApplicator(T applicator) where T : class, IApplyAbleSettings
+ /// 所有设置应用器的枚举集合
+ public IEnumerable AllApplicators()
+ => _applicators.Values;
+
+ ///
+ /// 注册设置应用器到模型中
+ ///
+ /// 设置应用器类型,必须实现IApplyAbleSettings接口
+ /// 要注册的设置应用器实例
+ /// 当前设置模型实例,支持链式调用
+ public ISettingsModel RegisterApplicator(T applicator)
+ where T : class, IApplyAbleSettings
{
- var type = typeof(T);
- _applicators[type] = applicator;
+ _applicators[typeof(T)] = applicator;
return this;
}
///
- /// 获取已注册的可应用设置
+ /// 获取指定类型的设置应用器实例
///
- /// 可应用设置类型,必须实现IApplyAbleSettings接口
- /// 找到的可应用设置实例,如果未找到则返回null
+ /// 设置应用器类型,必须实现IApplyAbleSettings接口
+ /// 指定类型的设置应用器实例,如果不存在则返回null
public T? GetApplicator() where T : class, IApplyAbleSettings
{
- var type = typeof(T);
- return _applicators.TryGetValue(type, out var applicator)
- ? (T)applicator
+ return _applicators.TryGetValue(typeof(T), out var app)
+ ? (T)app
: null;
}
- ///
- /// 获取所有设置数据
- ///
- /// 所有设置数据的枚举集合
- public IEnumerable AllData()
- {
- return _dataSettings.Values;
- }
+ // -----------------------------
+ // Section lookup
+ // -----------------------------
///
- /// 尝试获取指定类型的设置节
+ /// 尝试获取指定类型的设置节
///
/// 要查找的设置类型
/// 输出参数,找到的设置节实例
- /// 如果找到设置节则返回true,否则返回false
+ /// 如果找到对应类型的设置节则返回true,否则返回false
public bool TryGet(Type type, out ISettingsSection section)
{
- // 首先在数据设置字典中查找
if (_dataSettings.TryGetValue(type, out var data))
{
section = data;
return true;
}
- // 然后在应用器字典中查找
if (_applicators.TryGetValue(type, out var applicator))
{
section = applicator;
@@ -102,9 +107,49 @@ public class SettingsModel : AbstractModel, ISettingsModel
return false;
}
+ // -----------------------------
+ // Migration
+ // -----------------------------
///
- /// 初始化并加载指定类型的设置数据
+ /// 注册设置迁移器到模型中
+ ///
+ /// 要注册的设置迁移器实例
+ /// 当前设置模型实例,支持链式调用
+ public ISettingsModel RegisterMigration(ISettingsMigration migration)
+ {
+ _migrations[(migration.SettingsType, migration.FromVersion)] = migration;
+ return this;
+ }
+
+ ///
+ /// 如果需要的话,对设置节进行版本迁移
+ ///
+ /// 待检查和迁移的设置节
+ /// 迁移后的设置节
+ private ISettingsSection MigrateIfNeeded(ISettingsSection section)
+ {
+ if (section is not IVersioned versioned)
+ return section;
+
+ var type = section.GetType();
+ var current = section;
+
+ while (_migrations.TryGetValue((type, versioned.Version), out var migration))
+ {
+ current = migration.Migrate(current);
+ versioned = (IVersioned)current;
+ }
+
+ return current;
+ }
+
+ // -----------------------------
+ // Load / Init
+ // -----------------------------
+
+ ///
+ /// 异步初始化设置模型,加载指定类型的设置数据
///
/// 要初始化的设置类型数组
public async Task InitializeAsync(params Type[] settingTypes)
@@ -116,7 +161,7 @@ public class SettingsModel : AbstractModel, ISettingsModel
type.GetConstructor(Type.EmptyTypes) == null)
continue;
- // 使用反射调用泛型方法 LoadAsync
+ // Load()
var method = typeof(ISettingsPersistence)
.GetMethod(nameof(ISettingsPersistence.LoadAsync))!
.MakeGenericMethod(type);
@@ -124,14 +169,17 @@ public class SettingsModel : AbstractModel, ISettingsModel
var task = (Task)method.Invoke(_persistence, null)!;
await task;
- var loaded = (ISettingsData)((dynamic)task).Result;
- _dataSettings[type] = loaded;
+ var loaded = (ISettingsSection)((dynamic)task).Result;
+
+ // ★ 关键:迁移
+ var migrated = MigrateIfNeeded(loaded);
+
+ _dataSettings[type] = (ISettingsData)migrated;
}
}
-
///
- /// 初始化方法,用于执行模型的初始化逻辑
+ /// 初始化方法,用于获取设置持久化服务
///
protected override void OnInit()
{