除非setter是通用的,否则反序列化时JsonConvert不会初始化属性

Posted

技术标签:

【中文标题】除非setter是通用的,否则反序列化时JsonConvert不会初始化属性【英文标题】:JsonConvert not initialising properties when deserializing unless setter is generic 【发布时间】:2020-06-21 04:53:53 【问题描述】:

当 getter/setter 不是通用/默认值时,为什么 JsonConvert 无法初始化属性值。 例如,JsonConvert 将反序列化以下类(或者更确切地说是属性“值”)。假设我的 Json 文件包含 Value = 5,那么我的反序列化 SomeObjectX 对象将其属性“Value”设置为 5:

public class SomeClass

    public int Value  get; set; 

但是,如果我想让 setter 更复杂一些并做一些特别的事情,那么它就行不通了。这是新课程:

public class SomeClass

    public int MinValue  get; set; 
    public int MaxValue  get; set; 

    private int _value;
    public int Value
    
        get  return _value; 
        set
        
            // Restrict range to Min/Max
            if (MaxValue < value)
                _value = MaxValue;
            else if (MinValue > value)
                _value = MinValue;
            else
                _value = value;
        
    

关于信息,这里是我如何调用 JsonConvert 来反序列化为对象:

SomeClass SomeObjectX = JsonConvert.DeserializeObject<SomeClass>(File.ReadAllText(@"e:\someObject.json"), settings);

有没有办法让它发挥作用? 换句话说,如果我的 Json 包含 10 的初始化属性“Value”,那么我应该在反序列化时将“Value”设置为 10。

编辑

序列化的 Json 文件如下所示:


  "MaxValue": 10,
  "MinValue": 0,
  "Value": 5

这是我在运行时得到的未初始化对象(请参阅“值”应该是 0 而不是 5):

这是一个关于我如何创建对象实例、对其进行初始化、将其保存到 Json 并将其反序列化回对象的测试:

// Create and init object
var param = new SomeClass(); 
param.MaxValue = 10;
param.Value = 5;

// Settings - Not making any difference with or without
JsonSerializerSettings settings = new JsonSerializerSettings

    TypeNameHandling = TypeNameHandling.All,
    ObjectCreationHandling = ObjectCreationHandling.Replace
;

// Serialise into Json
File.WriteAllText(@"e:\param.json", JsonConvert.SerializeObject(param, settings));

// Deserialise back into object
SomeClass obj = JsonConvert.DeserializeObject<SomeClass>(File.ReadAllText(@"e:\param.json"), settings);

【问题讨论】:

json 包中是否有一个设置来控制字段是否优先于属性? 您的 JSON 文档是什么样的? @Neil,我不确定。刚刚为 Json 输入编辑了问题。 为了完全避免耦合,我建议通过构造函数传递所有 3 个值,并在那里执行检查。然后,使模型本身不可变。 至于手动排序,似乎可以使用[Order] 属性。 github.com/JamesNK/Newtonsoft.Json/issues/758 【参考方案1】:

您面临的问题似乎与属性的反序列化顺序有关。您的原始模型包含 ValueMaxValue 属性之间的时间耦合,并且根据您设置值的顺序,您最终会在对象上得到不同的结果。

您应该能够使用属性上的[Order] 属性来控制反序列化顺序,但我建议您改为使您的模型不可变,并通过构造函数传递所有 3 个值。这样,您还可以完全避免时间耦合,从而带来更好的设计。

【讨论】:

谢谢,我根据您在下面的输入添加了一个答案/示例。欢迎您检查并确认它是您的意思,谢谢:-)【参考方案2】:

使用 julealgon 的意见回答我的问题。 按照以下示例设置“JsonProperty Order”属性(“Value”需要使用最高订单号):

using Newtonsoft.Json;

public class SomeClass

    [JsonProperty(Order = 1)]
    public int MinValue  get; set; 

    [JsonProperty(Order = 2)]
    public int MaxValue  get; set; 

    private int _value;

    [JsonProperty(Order = 3)]
    public int Value
    
        get  return _value; 
        set
        
            // Restrict range to Min/Max
            if (MaxValue < value)
                _value = MaxValue;
            else if (MinValue > value)
                _value = MinValue;
            else
                _value = value;
        
    

这样 JsonConvert 将首先反序列化 MinValue 和 MaxValue,然后再反序列化 Value。

或者使用不可变属性:

public class SomeClass

    // Constructor
    public SomeClass(int, value, int minValue, int maxValue)
    
        MinValue = minValue;
        MaxValue = maxValue;
        // Set value after Min/MaxValue
        Value = value;
    
    public int MinValue  get; 
    public int MaxValue  get; 

    private int _value;
    public int Value
    
        get  return _value; 
        set
        
            // Restrict range to Min/Max
            if (MaxValue < value)
                _value = MaxValue;
            else if (MinValue > value)
                _value = MinValue;
            else
                _value = value;
        
    

【讨论】:

以上是关于除非setter是通用的,否则反序列化时JsonConvert不会初始化属性的主要内容,如果未能解决你的问题,请参考以下文章

fastjson反序列化多层嵌套泛型类与java中的Type类型

xmljson的序列化与反序列化

反序列化时忽略属性

Jackson 没有反序列化已序列化的通用列表

shiro的session信息放redis反序列化异常解决

网络安全Fastjson的反序列化漏洞复现