System.Text.Json反序列化私有成员值不符问题求助
问题概述
基于微软私有字段序列化示例实现的代码,对Brains.Brain的序列化过程正常,但反序列化后实例字段值不符合预期:实际得到(2, 0, 4, 4),预期应为(2, 3, 4, 7)。需要解决反序列化时构造函数的映射问题,以及序列化时的类型指定问题。
问题原因分析
- 序列化类型错误:
Loader.Save方法中,写入文件时未指定具体类型brainType,导致序列化的是IBrain接口而非Brain实现类。接口无任何可序列化字段,最终JSON文件未正确保存b和d的实际值。 - 构造函数映射失败:
Brain类仅提供带参构造函数,但参数名B与JSON字段名b不匹配,且未标记[JsonConstructor]特性。反序列化时无法正确将JSON字段映射到构造函数参数,导致调用构造函数时传入默认值0,进而计算出d=0+4=4。
解决方案
步骤1:修复序列化类型问题
修改Loader.Save方法中写入文件的代码,明确传入brainType,确保序列化的是Brain类的完整字段:
File.WriteAllText(fileName + ".json", JsonSerializer.Serialize(brain, brainType, options));
步骤2:正确配置构造函数映射
有两种方式解决构造函数参数与JSON字段的匹配问题:
方式一:修改构造函数参数名与字段名一致,并标记[JsonConstructor]
[JsonConstructor] public Brain(int b) { this.b = b; this.d = b + 4; }
方式二:保留原参数名,通过[JsonPropertyName]标记参数对应JSON字段
[JsonConstructor] public Brain([JsonPropertyName("b")] int B) { this.b = B; this.d = B + 4; }
补充说明
- 标记
[JsonConstructor]后,System.Text.Json会优先使用该构造函数创建实例,并将JSON中匹配的字段值传入参数。 - 字段初始化器(如
private int a = 2、public int c = 4)会在构造函数执行前运行,若JSON中存在对应字段值,会在实例创建后覆盖初始化值(此处a和c的JSON值与初始化值一致,结果不受影响)。
修改后的完整代码
using System.IO; using System.Linq; using System.Text.Json; using System.Reflection; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; namespace BinaryFiles { class Program { static void Main(string[] args) { Brains.Brain b = new(3); Type btype = typeof(Brains).GetNestedTypes().Where(brain => brain.GetInterface("IBrain") != null).ToArray()[0]; Loader.Save("test", b, btype); b.test(); IBrain newB = Loader.Load("test", btype); newB.test(); } } internal interface IBrain { void test(); } class Brains { [JsonIncludePrivateFields] public class Brain : IBrain { private int a = 2; private int b; public int c = 4; public int d; [JsonConstructor] public Brain(int b) { this.b = b; this.d = b + 4; } public void test() { Console.WriteLine($"{a} {b} {c} {d}"); } } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] public class JsonIncludePrivateFieldsAttribute : Attribute { } internal static class Loader { static void AddPrivateFieldsModifier(JsonTypeInfo jsonTypeInfo) { if (jsonTypeInfo.Kind != JsonTypeInfoKind.Object) return; if (!jsonTypeInfo.Type.IsDefined(typeof(JsonIncludePrivateFieldsAttribute), inherit: false)) return; foreach (FieldInfo field in jsonTypeInfo.Type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)) { JsonPropertyInfo jsonPropertyInfo = jsonTypeInfo.CreateJsonPropertyInfo(field.FieldType, field.Name); jsonPropertyInfo.Get = field.GetValue; jsonPropertyInfo.Set = field.SetValue; jsonTypeInfo.Properties.Add(jsonPropertyInfo); } } public static void Save(string fileName, IBrain brain, Type brainType) { var options = new JsonSerializerOptions { IncludeFields = true, WriteIndented = true, TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { AddPrivateFieldsModifier } } }; string json = JsonSerializer.Serialize(brain, brainType, options); Console.WriteLine(json); File.WriteAllText(fileName + ".json", json); } public static IBrain Load(string fileName, Type brainType) { var options = new JsonSerializerOptions { IncludeFields = true, WriteIndented = true, TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { AddPrivateFieldsModifier } } }; return (IBrain)JsonSerializer.Deserialize(File.ReadAllText(fileName + ".json"), brainType, options); } } }
内容的提问来源于stack exchange,提问作者Ioan
相关产品推荐
相关产品推荐

