diff --git a/GFramework.Game.Abstractions/data/DataRepositoryOptions.cs b/GFramework.Game.Abstractions/data/DataRepositoryOptions.cs new file mode 100644 index 0000000..f8134e2 --- /dev/null +++ b/GFramework.Game.Abstractions/data/DataRepositoryOptions.cs @@ -0,0 +1,40 @@ +// 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.data; + +/// +/// 数据仓库配置选项 +/// +public class DataRepositoryOptions +{ + /// + /// 存储基础路径(如 "user://data/") + /// + public string BasePath { get; set; } = ""; + + /// + /// 键名前缀(如 "Game",生成的键为 "Game_SettingsData") + /// + public string KeyPrefix { get; set; } = "Data"; + + /// + /// 是否在保存时自动备份 + /// + public bool AutoBackup { get; set; } = false; + + /// + /// 是否启用加载/保存事件 + /// + public bool EnableEvents { get; set; } = true; +} \ No newline at end of file diff --git a/GFramework.Game.Abstractions/data/IData.cs b/GFramework.Game.Abstractions/data/IData.cs new file mode 100644 index 0000000..ac834a8 --- /dev/null +++ b/GFramework.Game.Abstractions/data/IData.cs @@ -0,0 +1,19 @@ +// 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.data; + +/// +/// 通用数据标记接口 +/// +public interface IData; \ No newline at end of file diff --git a/GFramework.Game.Abstractions/data/IDataRepository.cs b/GFramework.Game.Abstractions/data/IDataRepository.cs new file mode 100644 index 0000000..a1b3ef0 --- /dev/null +++ b/GFramework.Game.Abstractions/data/IDataRepository.cs @@ -0,0 +1,54 @@ +// 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.data; + +/// +/// 定义数据仓库接口,提供异步的数据加载、保存、检查存在性和删除操作 +/// +public interface IDataRepository +{ + /// + /// 异步加载指定类型的数据对象 + /// + /// 要加载的数据类型,必须实现IData接口并具有无参构造函数 + /// 返回加载的数据对象的Task + Task LoadAsync() where T : class, IData, new(); + + /// + /// 异步保存指定的数据对象 + /// + /// 要保存的数据类型,必须实现IData接口 + /// 要保存的数据对象 + /// 表示异步保存操作的Task + Task SaveAsync(T data) where T : class, IData; + + /// + /// 异步检查指定类型的数据是否存在 + /// + /// 要检查的数据类型,必须实现IData接口 + /// 返回表示数据是否存在布尔值的Task + Task ExistsAsync() where T : class, IData; + + /// + /// 异步删除指定类型的数据 + /// + /// 要删除的数据类型,必须实现IData接口 + /// 表示异步删除操作的Task + Task DeleteAsync() where T : class, IData; + + /// + /// 批量保存多个数据 + /// + Task SaveAllAsync(IEnumerable dataList); +} \ No newline at end of file diff --git a/GFramework.Game.Abstractions/data/events/DataBatchSavedEvent.cs b/GFramework.Game.Abstractions/data/events/DataBatchSavedEvent.cs new file mode 100644 index 0000000..f45a295 --- /dev/null +++ b/GFramework.Game.Abstractions/data/events/DataBatchSavedEvent.cs @@ -0,0 +1,20 @@ +// 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.data.events; + +/// +/// 表示数据批次保存事件的记录类型 +/// +/// 包含已保存数据项的集合,实现了IData接口 +public sealed record DataBatchSavedEvent(ICollection List); \ No newline at end of file diff --git a/GFramework.Game.Abstractions/data/events/DataDeletedEvent.cs b/GFramework.Game.Abstractions/data/events/DataDeletedEvent.cs new file mode 100644 index 0000000..c05c3e0 --- /dev/null +++ b/GFramework.Game.Abstractions/data/events/DataDeletedEvent.cs @@ -0,0 +1,20 @@ +// 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.data.events; + +/// +/// 表示数据删除事件的记录类型 +/// +/// 被删除数据的类型 +public sealed record DataDeletedEvent(Type Type); \ No newline at end of file diff --git a/GFramework.Game.Abstractions/data/events/DataLoadedEvent.cs b/GFramework.Game.Abstractions/data/events/DataLoadedEvent.cs new file mode 100644 index 0000000..abd2f0a --- /dev/null +++ b/GFramework.Game.Abstractions/data/events/DataLoadedEvent.cs @@ -0,0 +1,21 @@ +// 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.data.events; + +/// +/// 表示数据加载完成事件的泛型类 +/// +/// 数据类型参数 +/// 加载完成的数据对象 +public sealed record DataLoadedEvent(T Data); \ No newline at end of file diff --git a/GFramework.Game.Abstractions/data/events/DataSavedEvent.cs b/GFramework.Game.Abstractions/data/events/DataSavedEvent.cs new file mode 100644 index 0000000..5a7ae28 --- /dev/null +++ b/GFramework.Game.Abstractions/data/events/DataSavedEvent.cs @@ -0,0 +1,21 @@ +// 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.data.events; + +/// +/// 表示数据保存事件的记录类型 +/// +/// 保存的数据类型 +/// 保存的数据实例 +public sealed record DataSavedEvent(T Data); \ No newline at end of file diff --git a/GFramework.Game.Abstractions/setting/IPersistentApplyAbleSettings.cs b/GFramework.Game.Abstractions/setting/IPersistentApplyAbleSettings.cs index 05479e5..3fcd1cb 100644 --- a/GFramework.Game.Abstractions/setting/IPersistentApplyAbleSettings.cs +++ b/GFramework.Game.Abstractions/setting/IPersistentApplyAbleSettings.cs @@ -17,4 +17,4 @@ namespace GFramework.Game.Abstractions.setting; /// 可持久化的应用设置接口 /// 同时具备数据持久化和应用逻辑能力 /// -public interface IPersistentApplyAbleSettings : ISettingsData, IApplyAbleSettings; \ No newline at end of file +public interface IPersistentApplyAbleSettings : IResettable, IApplyAbleSettings; \ No newline at end of file diff --git a/GFramework.Game.Abstractions/setting/ISettingsData.cs b/GFramework.Game.Abstractions/setting/IResettable.cs similarity index 52% rename from GFramework.Game.Abstractions/setting/ISettingsData.cs rename to GFramework.Game.Abstractions/setting/IResettable.cs index 7e8ce2e..f9947d4 100644 --- a/GFramework.Game.Abstractions/setting/ISettingsData.cs +++ b/GFramework.Game.Abstractions/setting/IResettable.cs @@ -1,9 +1,10 @@ namespace GFramework.Game.Abstractions.setting; /// -/// 设置数据接口 - 纯数据,可自动创建 +/// 可重置设置接口,继承自ISettingsSection接口 +/// 提供将设置重置为默认值的功能 /// -public interface ISettingsData : ISettingsSection +public interface IResettable : ISettingsSection { /// /// 重置设置为默认值 diff --git a/GFramework.Game.Abstractions/setting/ISettingsModel.cs b/GFramework.Game.Abstractions/setting/ISettingsModel.cs index fb3e2b4..d48f98b 100644 --- a/GFramework.Game.Abstractions/setting/ISettingsModel.cs +++ b/GFramework.Game.Abstractions/setting/ISettingsModel.cs @@ -12,7 +12,7 @@ public interface ISettingsModel : IModel /// /// 设置数据的类型,必须继承自class、ISettingsData且具有无参构造函数 /// 指定类型的设置数据实例 - T GetData() where T : class, ISettingsData, new(); + T GetData() where T : class, IResettable, new(); /// /// 尝试获取指定类型的设置节实例 @@ -33,7 +33,7 @@ public interface ISettingsModel : IModel /// 获取所有设置数据的集合 /// /// 包含所有设置数据的可枚举集合 - IEnumerable AllData(); + IEnumerable AllData(); /// /// 获取所有可应用设置的集合 diff --git a/GFramework.Game.Abstractions/setting/ISettingsPersistence.cs b/GFramework.Game.Abstractions/setting/ISettingsPersistence.cs index 56673db..00280ae 100644 --- a/GFramework.Game.Abstractions/setting/ISettingsPersistence.cs +++ b/GFramework.Game.Abstractions/setting/ISettingsPersistence.cs @@ -11,25 +11,25 @@ public interface ISettingsPersistence : IContextUtility /// /// 异步加载指定类型的设置数据 /// - Task LoadAsync() where T : class, ISettingsData, new(); + Task LoadAsync() where T : class, IResettable, new(); /// /// 异步保存指定的设置数据 /// - Task SaveAsync(T section) where T : class, ISettingsData; + Task SaveAsync(T section) where T : class, IResettable; /// /// 异步检查指定类型的设置数据是否存在 /// - Task ExistsAsync() where T : class, ISettingsData; + Task ExistsAsync() where T : class, IResettable; /// /// 异步删除指定类型的设置数据 /// - Task DeleteAsync() where T : class, ISettingsData; + Task DeleteAsync() where T : class, IResettable; /// /// 保存所有设置数据 /// - Task SaveAllAsync(IEnumerable allData); + Task SaveAllAsync(IEnumerable allData); } \ No newline at end of file diff --git a/GFramework.Game.Abstractions/setting/data/AudioSettings.cs b/GFramework.Game.Abstractions/setting/data/AudioSettings.cs index 2e07a5f..e888a67 100644 --- a/GFramework.Game.Abstractions/setting/data/AudioSettings.cs +++ b/GFramework.Game.Abstractions/setting/data/AudioSettings.cs @@ -5,7 +5,7 @@ namespace GFramework.Game.Abstractions.setting.data; /// /// 音频设置类,用于管理游戏中的音频配置 /// -public class AudioSettings : ISettingsData, IVersioned +public class AudioSettings : IResettable, IVersioned { /// /// 获取或设置主音量,控制所有音频的总体音量 diff --git a/GFramework.Game.Abstractions/setting/data/GraphicsSettings.cs b/GFramework.Game.Abstractions/setting/data/GraphicsSettings.cs index fe721ef..4415a2e 100644 --- a/GFramework.Game.Abstractions/setting/data/GraphicsSettings.cs +++ b/GFramework.Game.Abstractions/setting/data/GraphicsSettings.cs @@ -5,7 +5,7 @@ namespace GFramework.Game.Abstractions.setting.data; /// /// 图形设置类,用于管理游戏的图形相关配置 /// -public class GraphicsSettings : ISettingsData, IVersioned +public class GraphicsSettings : IResettable, IVersioned { /// /// 获取或设置是否启用全屏模式 diff --git a/GFramework.Game.Abstractions/setting/data/LocalizationSettings.cs b/GFramework.Game.Abstractions/setting/data/LocalizationSettings.cs index a998047..a894464 100644 --- a/GFramework.Game.Abstractions/setting/data/LocalizationSettings.cs +++ b/GFramework.Game.Abstractions/setting/data/LocalizationSettings.cs @@ -19,7 +19,7 @@ namespace GFramework.Game.Abstractions.setting.data; /// 本地化设置类,用于管理游戏的语言本地化配置 /// 实现了ISettingsData接口提供设置数据功能,实现IVersioned接口提供版本控制功能 /// -public class LocalizationSettings : ISettingsData, IVersioned +public class LocalizationSettings : IResettable, IVersioned { /// /// 获取或设置当前使用的语言 diff --git a/GFramework.Game/data/DataRepository.cs b/GFramework.Game/data/DataRepository.cs new file mode 100644 index 0000000..599ad2b --- /dev/null +++ b/GFramework.Game/data/DataRepository.cs @@ -0,0 +1,153 @@ +// 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. + +using GFramework.Core.Abstractions.storage; +using GFramework.Core.extensions; +using GFramework.Core.utility; +using GFramework.Game.Abstractions.data; +using GFramework.Game.Abstractions.data.events; + +namespace GFramework.Game.data; + +/// +/// 数据仓库类,用于管理游戏数据的存储和读取 +/// +/// 存储接口实例 +/// 数据仓库配置选项 +public class DataRepository(IStorage? storage, DataRepositoryOptions? options = null) + : AbstractContextUtility, IDataRepository +{ + private readonly DataRepositoryOptions _options = options ?? new DataRepositoryOptions(); + private IStorage? _storage = storage; + + private IStorage Storage => _storage ?? + throw new InvalidOperationException( + "Failed to initialize storage. No IStorage utility found in context."); + + /// + /// 异步加载指定类型的数据 + /// + /// 要加载的数据类型,必须实现IData接口 + /// 加载的数据对象 + public async Task LoadAsync() where T : class, IData, new() + { + var key = GetKey(); + + T result; + if (await Storage.ExistsAsync(key)) + { + result = await Storage.ReadAsync(key); + } + else + { + result = new T(); + } + + if (_options.EnableEvents) + this.SendEvent(new DataLoadedEvent(result)); + + return result; + } + + /// + /// 异步保存指定类型的数据 + /// + /// 要保存的数据类型 + /// 要保存的数据对象 + public async Task SaveAsync(T data) where T : class, IData + { + var key = GetKey(); + + // 自动备份 + if (_options.AutoBackup && await Storage.ExistsAsync(key)) + { + var backupKey = $"{key}.backup"; + var existing = await Storage.ReadAsync(key); + await Storage.WriteAsync(backupKey, existing); + } + + await Storage.WriteAsync(key, data); + + if (_options.EnableEvents) + this.SendEvent(new DataSavedEvent(data)); + } + + /// + /// 检查指定类型的数据是否存在 + /// + /// 要检查的数据类型 + /// 如果数据存在返回true,否则返回false + public async Task ExistsAsync() where T : class, IData + { + var key = GetKey(); + return await Storage.ExistsAsync(key); + } + + /// + /// 异步删除指定类型的数据 + /// + /// 要删除的数据类型 + public async Task DeleteAsync() where T : class, IData + { + var key = GetKey(); + await Storage.DeleteAsync(key); + + if (_options.EnableEvents) + this.SendEvent(new DataDeletedEvent(typeof(T))); + } + + /// + /// 批量异步保存多个数据对象 + /// + /// 要保存的数据对象集合 + public async Task SaveAllAsync(IEnumerable dataList) + { + var list = dataList.ToList(); + foreach (var data in list) + { + var type = data.GetType(); + var key = GetKey(type); + await Storage.WriteAsync(key, data); + } + + if (_options.EnableEvents) + this.SendEvent(new DataBatchSavedEvent(list)); + } + + protected override void OnInit() + { + _storage ??= this.GetUtility()!; + } + + /// + /// 根据类型生成存储键 + /// + /// 数据类型 + /// 生成的存储键 + private string GetKey() where T : IData => GetKey(typeof(T)); + + /// + /// 根据类型生成存储键 + /// + /// 数据类型 + /// 生成的存储键 + private string GetKey(Type type) + { + var fileName = $"{_options.KeyPrefix}_{type.Name}"; + + if (string.IsNullOrEmpty(_options.BasePath)) + return fileName; + var basePath = _options.BasePath.TrimEnd('/'); + return $"{basePath}/{fileName}"; + } +} \ No newline at end of file diff --git a/GFramework.Game/setting/SettingsModel.cs b/GFramework.Game/setting/SettingsModel.cs index 055c2c2..9c18cb7 100644 --- a/GFramework.Game/setting/SettingsModel.cs +++ b/GFramework.Game/setting/SettingsModel.cs @@ -16,7 +16,7 @@ public class SettingsModel : AbstractModel, ISettingsModel { private static readonly ILogger Log = LoggerFactoryResolver.Provider.CreateLogger(nameof(SettingsModel)); private readonly ConcurrentDictionary _applicators = new(); - private readonly ConcurrentDictionary _dataSettings = new(); + private readonly ConcurrentDictionary _dataSettings = new(); private readonly ConcurrentDictionary _loadAsyncMethodCache = new(); private readonly ConcurrentDictionary> _migrationCache = new(); private readonly ConcurrentDictionary<(Type type, int from), ISettingsMigration> _migrations = new(); @@ -31,7 +31,7 @@ public class SettingsModel : AbstractModel, ISettingsModel /// /// 设置数据类型,必须实现ISettingsData接口并提供无参构造函数 /// 指定类型的设置数据实例 - public T GetData() where T : class, ISettingsData, new() + public T GetData() where T : class, IResettable, new() { return (T)_dataSettings.GetOrAdd(typeof(T), _ => new T()); } @@ -40,7 +40,7 @@ public class SettingsModel : AbstractModel, ISettingsModel /// 获取所有设置数据的枚举集合 /// /// 所有设置数据的枚举集合 - public IEnumerable AllData() + public IEnumerable AllData() => _dataSettings.Values; // ----------------------------- @@ -166,7 +166,7 @@ public class SettingsModel : AbstractModel, ISettingsModel { foreach (var type in settingTypes) { - if (!typeof(ISettingsData).IsAssignableFrom(type) || + if (!typeof(IResettable).IsAssignableFrom(type) || !type.IsClass || type.GetConstructor(Type.EmptyTypes) == null) continue; @@ -182,7 +182,7 @@ public class SettingsModel : AbstractModel, ISettingsModel var loaded = (ISettingsSection)((dynamic)task).Result; var migrated = MigrateIfNeeded(loaded); - _dataSettings[type] = (ISettingsData)migrated; + _dataSettings[type] = (IResettable)migrated; _migrationCache.TryRemove(type, out _); } catch (Exception ex) diff --git a/GFramework.Game/setting/SettingsPersistence.cs b/GFramework.Game/setting/SettingsPersistence.cs index 63a3edf..27987b3 100644 --- a/GFramework.Game/setting/SettingsPersistence.cs +++ b/GFramework.Game/setting/SettingsPersistence.cs @@ -18,7 +18,7 @@ public class SettingsPersistence : AbstractContextUtility, ISettingsPersistence /// /// 设置数据类型,必须实现ISettingsData接口 /// 如果存在则返回存储的设置数据,否则返回新创建的实例 - public async Task LoadAsync() where T : class, ISettingsData, new() + public async Task LoadAsync() where T : class, IResettable, new() { var key = GetKey(); @@ -39,7 +39,7 @@ public class SettingsPersistence : AbstractContextUtility, ISettingsPersistence /// /// 设置数据类型,必须实现ISettingsData接口 /// 要保存的设置数据实例 - public async Task SaveAsync(T section) where T : class, ISettingsData + public async Task SaveAsync(T section) where T : class, IResettable { var key = GetKey(); await _storage.WriteAsync(key, section); @@ -51,7 +51,7 @@ public class SettingsPersistence : AbstractContextUtility, ISettingsPersistence /// /// 设置数据类型,必须实现ISettingsData接口 /// 如果存在返回true,否则返回false - public async Task ExistsAsync() where T : class, ISettingsData + public async Task ExistsAsync() where T : class, IResettable { var key = GetKey(); return await _storage.ExistsAsync(key); @@ -61,7 +61,7 @@ public class SettingsPersistence : AbstractContextUtility, ISettingsPersistence /// 异步删除指定类型的设置数据 /// /// 设置数据类型,必须实现ISettingsData接口 - public async Task DeleteAsync() where T : class, ISettingsData + public async Task DeleteAsync() where T : class, IResettable { var key = GetKey(); await _storage.DeleteAsync(key); @@ -73,7 +73,7 @@ public class SettingsPersistence : AbstractContextUtility, ISettingsPersistence /// 异步保存所有设置数据到存储中 /// /// 包含所有设置数据的可枚举集合 - public async Task SaveAllAsync(IEnumerable allData) + public async Task SaveAllAsync(IEnumerable allData) { var dataList = allData.ToList(); foreach (var data in dataList) @@ -96,7 +96,7 @@ public class SettingsPersistence : AbstractContextUtility, ISettingsPersistence /// /// 设置数据类型 /// 格式为"Settings_类型名称"的键名 - private static string GetKey() where T : ISettingsData + private static string GetKey() where T : IResettable { return GetKey(typeof(T)); } diff --git a/GFramework.Game/setting/events/SettingsBatchChangedEvent.cs b/GFramework.Game/setting/events/SettingsBatchChangedEvent.cs index 1ac3bc8..c54a737 100644 --- a/GFramework.Game/setting/events/SettingsBatchChangedEvent.cs +++ b/GFramework.Game/setting/events/SettingsBatchChangedEvent.cs @@ -7,12 +7,12 @@ namespace GFramework.Game.setting.events; /// 表示多个设置项同时发生变更的事件 /// /// 发生变更的设置数据集合 -public class SettingsBatchChangedEvent(IEnumerable settings) : ISettingsChangedEvent +public class SettingsBatchChangedEvent(IEnumerable settings) : ISettingsChangedEvent { /// /// 获取发生变更的具体设置数据列表 /// - public IEnumerable ChangedSettings { get; } = settings.ToList(); + public IEnumerable ChangedSettings { get; } = settings.ToList(); /// /// 获取设置类型,对于批量变更事件,固定返回ISettingsSection类型 diff --git a/GFramework.Game/setting/events/SettingsBatchSavedEvent.cs b/GFramework.Game/setting/events/SettingsBatchSavedEvent.cs index 0e94952..d4fb426 100644 --- a/GFramework.Game/setting/events/SettingsBatchSavedEvent.cs +++ b/GFramework.Game/setting/events/SettingsBatchSavedEvent.cs @@ -6,12 +6,12 @@ namespace GFramework.Game.setting.events; /// 表示设置批量保存事件 /// /// 要保存的设置数据集合 -public class SettingsBatchSavedEvent(IEnumerable settings) : ISettingsChangedEvent +public class SettingsBatchSavedEvent(IEnumerable settings) : ISettingsChangedEvent { /// /// 获取已保存的设置数据只读集合 /// - public IReadOnlyCollection SavedSettings { get; } = settings.ToList(); + public IReadOnlyCollection SavedSettings { get; } = settings.ToList(); /// /// 获取设置类型(始终返回ISettingsSection类型)