You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

System.Text.Json反序列化私有成员值不符问题求助

问题概述

基于微软私有字段序列化示例实现的代码,对Brains.Brain的序列化过程正常,但反序列化后实例字段值不符合预期:实际得到(2, 0, 4, 4),预期应为(2, 3, 4, 7)。需要解决反序列化时构造函数的映射问题,以及序列化时的类型指定问题。

问题原因分析
  1. 序列化类型错误:Loader.Save方法中,写入文件时未指定具体类型brainType,导致序列化的是IBrain接口而非Brain实现类。接口无任何可序列化字段,最终JSON文件未正确保存b和d的实际值。
  2. 构造函数映射失败: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 16:33:17