如何更好地封装标记为[Serializable]的C#类成员变量?
封装可序列化数据类的实现方案
针对你遇到的问题——既要用Newtonsoft JSON.NET序列化数据,又要防止外部直接修改PlayerGlobalAggregateData的字段,可以通过以下几步实现封装:
1. 改造数据类:私有字段+JsonProperty标记+受控访问
把原来的public字段改为private,用[JsonProperty]标记让JSON.NET可以序列化/反序列化私有字段,同时提供只读属性供外部获取数据,只暴露受控的修改方法给授权类(比如你的ScriptableObject)。
[Serializable] public class PlayerGlobalAggregateData { // 用JsonProperty标记私有字段,让JSON.NET能处理序列化 [JsonProperty("total_score")] private int _totalScore; [JsonProperty("play_count")] private int _playCount; // 只读属性,外部只能获取不能修改 public int TotalScore => _totalScore; public int PlayCount => _playCount; // 内部修改方法,只允许ScriptableObject等授权类调用 internal void AddScore(int score) { _totalScore = Math.Max(0, _totalScore + score); // 可在此添加业务校验逻辑 } internal void IncrementPlayCount() { _playCount++; } }
2. 优化ScriptableObject:屏蔽直接数据访问,提供受控接口
不再直接返回_data实例,而是暴露只读数据获取方法和受控修改方法,同时内部处理序列化/反序列化逻辑,不让外部拿到可修改的数据对象。
public class PlayerGlobalAggregateModel : ScriptableObject { private PlayerGlobalAggregateData _data; // 加载数据时做深拷贝,防止外部传入的对象被修改影响内部状态 public void SetModelData(PlayerGlobalAggregateData loadedData) { if (loadedData == null) { _data = new PlayerGlobalAggregateData(); return; } // 用JSON序列化再反序列化实现深拷贝 _data = JsonConvert.DeserializeObject<PlayerGlobalAggregateData>( JsonConvert.SerializeObject(loadedData) ); } // 外部获取数据的只读接口 public int GetTotalScore() => _data.TotalScore; public int GetPlayCount() => _data.PlayCount; // 受控的修改方法,集中处理业务逻辑 public void RecordPlayerScore(int score) { _data.AddScore(score); } public void LogPlaySession() { _data.IncrementPlayCount(); } // 内部处理保存逻辑,不让外部接触原始数据 public void SaveDataToFile(string filePath) { string json = JsonConvert.SerializeObject(_data, Formatting.Indented); File.WriteAllText(filePath, json); } }
3. 可选:用只读接口进一步限制访问
如果需要更严格的访问控制,可以定义一个只读接口,让数据类实现该接口,ScriptableObject只返回接口类型,外部完全无法看到修改方法:
// 只读接口,只包含获取数据的属性 public interface IReadOnlyPlayerData { int TotalScore { get; } int PlayCount { get; } } // 数据类实现接口 [Serializable] public class PlayerGlobalAggregateData : IReadOnlyPlayerData { [JsonProperty] private int _totalScore; [JsonProperty] private int _playCount; // 实现接口的只读属性 public int TotalScore => _totalScore; public int PlayCount => _playCount; // 内部修改方法... } // 在ScriptableObject中添加只读数据返回方法 public IReadOnlyPlayerData GetReadOnlyPlayerData() => _data;
核心原理说明
[JsonProperty]标记:Newtonsoft JSON.NET支持序列化私有字段,只要用该标签标记,就能正常读写JSON文件,无需保持字段为public。- 受控修改:所有数据修改都通过ScriptableObject提供的方法完成,集中处理业务校验(比如分数不能为负),避免外部随意修改导致数据不一致。
- 深拷贝:加载数据时做深拷贝,防止外部传入的原始对象被修改后影响ScriptableObject内部的状态。
内容的提问来源于stack exchange,提问作者Janesh Parnami
相关产品推荐
相关产品推荐

