如何使用Json.NET仅序列化/反序列化类型的指定私有字段?
仅序列化指定私有字段的Json.NET实现方案
问题背景
需要对MyClass类型仅序列化/反序列化指定的私有字段,忽略其他所有公开/私有字段及属性。当前采用Dictionary<string, object>作为中间类型的方案,序列化正常,但反序列化时因字典中object值类型不匹配、反射逻辑错误导致失败。
解决方案
方案一:自定义JsonConverter(推荐)
直接通过自定义JsonConverter控制序列化和反序列化过程,无需中间字典,更贴合Json.NET的设计思路。
实现自定义转换器
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Reflection; using System.Collections.Generic; public class MyClassConverter : JsonConverter<MyClass> { // 明确要序列化的私有字段列表 private readonly HashSet<string> _targetFields = new HashSet<string> { nameof(MyClass.SomeParameters), nameof(MyClass.notifications), nameof(MyClass.someKey), nameof(MyClass.someNumber), nameof(MyClass.aChar) }; public override void WriteJson(JsonWriter writer, MyClass? value, JsonSerializer serializer) { if (value == null) { writer.WriteNull(); return; } writer.WriteStartObject(); // 反射获取目标私有字段并序列化 foreach (var fieldName in _targetFields) { var field = typeof(MyClass).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); if (field != null) { var fieldValue = field.GetValue(value); writer.WritePropertyName(fieldName); serializer.Serialize(writer, fieldValue); } } writer.WriteEndObject(); } public override MyClass? ReadJson(JsonReader reader, Type objectType, MyClass? existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; var instance = existingValue ?? new MyClass(); var jsonObj = JObject.Load(reader); // 反射设置目标私有字段 foreach (var fieldName in _targetFields) { var field = typeof(MyClass).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); if (field != null && jsonObj.TryGetValue(fieldName, StringComparison.OrdinalIgnoreCase, out var token)) { var fieldValue = token.ToObject(field.FieldType, serializer); field.SetValue(instance, fieldValue); } } return instance; } }
使用方式
序列化/反序列化时指定转换器即可:
// 序列化示例 var myObj = new MyClass( new Dictionary<string, Parameters> { { "name", new Parameters("hello", "There") } }, new NotificationList(), "some key", 101, 'z' ); string json = JsonConvert.SerializeObject(myObj, new MyClassConverter()); // 反序列化示例 var deserializedObj = JsonConvert.DeserializeObject<MyClass>(json, new MyClassConverter());
方案二:修复原有Dictionary方案
如果坚持使用中间字典,需要解决两个核心问题:
- 反射时错误获取了
Dictionary<string,object>的字段,而非MyClass的字段 - 反序列化字典时需将
object值转换为字段实际类型
修复后的FromDictionary方法
public partial class MyClass { public Dictionary<string, object> ToDictionary() => new() { { nameof(SomeParameters), SomeParameters}, { nameof(notifications), notifications }, { nameof(someKey), someKey }, { nameof(someNumber), someNumber }, { nameof(aChar), aChar }, }; public static MyClass FromDictionary(Dictionary<string, object> settings) { var instance = new MyClass(); var myClassType = typeof(MyClass); foreach (var kvp in settings) { // 正确获取MyClass的私有字段 FieldInfo? fieldInfo = myClassType.GetField(kvp.Key, BindingFlags.NonPublic | BindingFlags.Instance); if (fieldInfo == null) continue; // 将字典中的object值转换为字段实际类型 var fieldValue = JsonConvert.DeserializeObject( JsonConvert.SerializeObject(kvp.Value), fieldInfo.FieldType ); fieldInfo.SetValue(instance, fieldValue); } return instance; } }
反序列化字典的正确流程
// 序列化字典 string json = JsonConvert.SerializeObject(myObj.ToDictionary()); // 反序列化并重建实例 var settingsDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(json); var restoredObj = MyClass.FromDictionary(settingsDict);
关键说明
- 自定义Converter方案无需额外中间类型,直接控制序列化逻辑,类型安全且性能更优
- 修复Dictionary方案时,核心是正确反射目标类的字段和将object值转换为字段实际类型
内容的提问来源于stack exchange,提问作者livan3li
相关产品推荐
相关产品推荐

