属性绑定式的响应——全自动序列化和反序列化
昨天在做游戏配置项的本地化存储
想着把这个东西做的智能一点 完全不需要操心序列化的时机和反序列化的时机
所以就考虑了属性绑定式的响应
去监听属性的修改 只要有属性被修改就能够自动被序列化到本地
求助了一下万能的gpt 在它的帮助下最终实现是这样的
using System;
using UnityEngine;
using System.ComponentModel;
[Serializable]
public class GameSetting : INotifyPropertyChanged
{
[SerializeField]
private bool birthPlace = true;
public bool BirthPlace
{
get => birthPlace;
set
{
if (birthPlace != value)
{
birthPlace = value;
OnPropertyChanged(nameof(BirthPlace));
}
}
}
[SerializeField]
private bool test_0 = true;
public bool Test_0
{
get => test_0;
set
{
if (test_0 != value)
{
test_0 = value;
OnPropertyChanged(nameof(test_0));
}
}
}
//新增属性只要像Test_0这样就可以了
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class GameSettingManager
{
private static readonly string KEY = "GameSetting";
public static GameSettingManager Instance { get; } = new GameSettingManager();
private GameSetting config;
public GameSetting Config
{
get
{
if (config == null)
{
//单例内的config为空的时候 要去反序列化一遍
config = LoadGameSetting();
//注册一下监听的方法
config.PropertyChanged += OnConfigPropertyChanged;
}
return config;
}
set
{
if (value == null)
{
Debug.LogError("不能空 如果要直接Set一定要传值");
}
if (config != null)
{
//不为空 先取消旧的监听事件
config.PropertyChanged -= OnConfigPropertyChanged;
}
config = value;
//重新修改后 要再添加新的监听事件
config.PropertyChanged += OnConfigPropertyChanged;
SaveGameSetting(config);
}
}
private GameSettingManager()
{
if (Instance != null)
{
Debug.LogError("出现了多个游戏设置单例,要检查一下为什么");
}
}
/// <summary>
/// 保存游戏设置
/// </summary>
/// <param name="config"></param>
private void SaveGameSetting(GameSetting config)
{
string json = JsonUtility.ToJson(config);
PlayerPrefs.SetString(KEY, json);
Debug.Log("触发游戏设置序列化操作" + json);
}
/// <summary>
/// 加载游戏设置
/// </summary>
/// <returns></returns>
private GameSetting LoadGameSetting()
{
if (PlayerPrefs.HasKey(KEY))
{
string json = PlayerPrefs.GetString(KEY);
Debug.Log("触发游戏设置反序列化操作" + json);
var config = JsonUtility.FromJson<GameSetting>(json);
//每次新的对象都要注册一下
config.PropertyChanged += OnConfigPropertyChanged;
return config;
}
else
{
//没有的话就创建一个新的 参数都给默认值
var config = new GameSetting { BirthPlace = true };
//同上 新对象都要注册一下
config.PropertyChanged += OnConfigPropertyChanged;
SaveGameSetting(config);
return config;
}
}
private void OnConfigPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (sender == Config)
{
//在这里还可以通过判断e的属性名来做不同的操作
switch (e.PropertyName)
{
case nameof(GameSetting.BirthPlace):
// 处理 BirthPlace 属性改变的逻辑
break;
case nameof(GameSetting.Test_0):
// 处理 Test_0 属性改变的逻辑
break;
// 添加其他属性的处理逻辑
default:
break;
}
SaveGameSetting(Config);
}
}
}这个方法缺点也很明显
全自动看起来很高端 但完全不可控
假如说有一个玩家很手贱 一直在修改这些配置
那序列化就会在短时间内一直发生
可能会引起比较明显的卡顿的现象
所以最终老大哥没有采用这个方案
还是选了最简单的 把序列化暴露出来交给外面控制
当然你还可以用比较古典的SetDirty的方法
做一下标记 退出页面的时候只要带有脏标记就弹窗提示一下保存