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

如何使用System.Text.Json反序列化含无参公共构造函数的类

问题:带公共无参构造函数的C#类反序列化时属性无法正确赋值

在.NET 7.0的C#应用中,使用System.Text.Json进行序列化/反序列化时出现异常:

  • 类Works(私有无参构造+公共有参构造)反序列化后,address能正确获取JSON中的值"abc"
  • 类Doesnt(标记[JsonConstructor]的公共无参构造+公共有参构造)反序列化后,address始终是无参构造里的"default"(移除初始化则为null)

示例代码

正常工作的Works类

public class Works
{
    public string address { get; private set; }

    Works()
    {
        address = "default";
    }
    public Works(string address)
    {
        this.address = address;
    }
}

反序列化异常的Doesnt类

public class Doesnt
{
    public string address { get; private set; }

    [JsonConstructor] 
    public Doesnt()
    {
        address = "default";
    }
    public Doesnt(string address)
    {
        this.address = address;
    }
}

序列化与反序列化逻辑

public byte[] SerializeToBytes<T>(T src)
{
    return JsonSerializer.SerializeToUtf8Bytes(src, SerializerOptions);
}
public object Deserialize(byte[] data, Type type)
{
    object res;
    var str = System.Text.Encoding.UTF8.GetString(data);
    res = JsonSerializer.Deserialize(str, type, SerializerOptions);
    return res;
}

var objs = new object[]{new Works("abc"),new Doesnt("abc")};
var bytes = SerializeToBytes(objs[0]);
Deserialize(bytes, objs[0].GetType());// 返回"abc"

bytes = SerializeToBytes(objs[1]);
Deserialize(bytes, objs[1].GetType()); // 返回"default"

解决方案

方法1:将[JsonConstructor]标记移至有参构造函数

把[JsonConstructor]从无参构造转移到接收address参数的有参构造上,让反序列化时优先调用该构造,直接用JSON中的值初始化属性:

public class Doesnt
{
    public string address { get; private set; }

    public Doesnt()
    {
        address = "default";
    }

    [JsonConstructor] // 标记有参构造
    public Doesnt(string address)
    {
        this.address = address;
    }
}

说明:此方法会跳过无参构造的执行逻辑,直接通过JSON值初始化对象,适合不需要保留无参构造初始化逻辑的场景。

方法2:给私有setter添加[JsonInclude]特性

通过[JsonInclude]允许System.Text.Json访问私有setter,这样反序列化时会先执行无参构造初始化,再用JSON值覆盖属性:

public class Doesnt
{
    [JsonInclude] // 允许序列化/反序列化访问私有setter
    public string address { get; private set; }

    [JsonConstructor]
    public Doesnt()
    {
        address = "default";
    }

    public Doesnt(string address)
    {
        this.address = address;
    }
}

说明:此方法会保留无参构造的初始化逻辑,再用JSON值覆盖属性,适合需要保留默认初始化逻辑的场景。


内容的提问来源于stack exchange,提问作者Maxim Kitsenko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 04:05:33