1. 咖啡咖 2025-11-12

    原来是这样的原因,学到了!

  2. compass 2025-11-17

    坑2:C#中用json序列化方式读取并生成的类对象,不会触发调用构造函数
    如果在构造函数中设置了id的自增,则会发现id没有变化


    是的,你的观察是正确的。
    在 C# 中,当你使用常见的 JSON 序列化/反序列化库(例如 Newtonsoft.Json、System.Text.Json)去 反序列化 JSON 字符串成为一个类对象时,默认情况下不会调用类的普通构造函数。

    1. 为什么构造函数不会被调用?

    JSON 反序列化过程本质上是通过反射直接创建对象实例并为其字段/属性赋值,而不是像 new MyClass() 那样调用构造函数。

    以 Newtonsoft.Json 为例:

    默认反序列化时会用 FormatterServices.GetUninitializedObject()(或类似机制)在内存中分配对象,不走用户定义的构造函数。
    然后根据 JSON 字段,把属性或字段的值用反射赋进去。

    System.Text.Json(.NET Core 3.1+)则:

    默认使用无参数构造函数(如果存在且可访问)。
    如果类没有无参构造函数,就用非常规实例化方式(类似反射直接创建),绕过你的自定义构造函数逻辑。
    2. 如何让反序列化调用构造函数?

    如果你的反序列化需要执行构造函数逻辑(比如初始化某些数据),需要做以下处理:

    Newtonsoft.Json
    确保类具有公共或私有的无参构造函数。
    如果想绑定到特定构造函数,可以使用 [JsonConstructor] 特性,例如:
    csharp
    复制代码
    收起
    public class Person
    {
    public string Name { get; }
    public int Age { get; }

    [JsonConstructor]
    public Person(string name, int age)
    {
    Console.WriteLine("构造函数调用!");
    Name = name;
    Age = age;
    }
    }
    复制

    这样在反序列化时会调用该构造函数。

    System.Text.Json
    必须有一个适用的构造器(public 或 internal),且参数名与 JSON 属性匹配。
    用 [JsonConstructor] 明确标记要用的构造函数。
    csharp
    复制代码
    收起
    public class Person
    {
    public string Name { get; }
    public int Age { get; }

    [JsonConstructor]
    public Person(string name, int age)
    {
    Console.WriteLine("构造函数调用!");
    Name = name;
    Age = age;
    }
    }
    复制
    3. 总结
    默认反序列化:很可能绕过你自定义的构造函数(特别是 Newtonsoft.Json)。
    需要构造器逻辑:使用 [JsonConstructor] 或提供无参构造函数。
    初始化逻辑替代:如果不能依赖构造函数,可用反序列化回调特性:
    Newtonsoft.Json: IJsonSerializable、OnDeserialized 属性。
    System.Text.Json: OnDeserialized 方法在较新版本里可支持(.NET 8+)。

    如果你愿意的话,我可以帮你写一个 Newtonsoft.Json 和 System.Text.Json 的反序列化对比示例,让你直观看到构造函数是否被调用以及如何强制调用。
    你要我帮你做这个演示吗?

您需要登录或者注册后才能发表评论

登录/注册