【问题标题】:Newtonsoft.Json De-Serialization does not override a property set in constructorNewtonsoft.Json 反序列化不会覆盖构造函数中设置的属性
【发布时间】:2020-09-01 02:53:10
【问题描述】:

上下文

我有一个类要使用 Newtonsoft.Json 进行序列化和反序列化。

我的想法是在构造函数中给某些字段设置默认值,所以在反序列化过程中,如果缺少某个值,则假定为默认值。 然而,令我惊讶的是,反序列化器不会将默认值替换为 JSON 字符串中的值。

代码

public class MyClass {

    public int Key { get; set; }

    private void LoadDefaults() {
        Key = 1;
    }

    public MyClass() {
        LoadDefaults();
    }
}

从上面的类中序列化一个实例后,我得到了这个 JSON:

{    "Key": 2    }

然后我用这个反序列化它:

public void Deserialize(Stream input, out MyClass output) {
    using (var sr = new StreamReader(input)) {
        using (var jr = new JsonTextReader(sr)) {
            var serializer = new JsonSerializer();
            output = serializer.Deserialize<MyClass>(jr);
        }
    }
}

我希望反序列化器首先调用“MyClass”的构造函数,然后调用 LoadDefaults(); 一切似乎都按预期发生。但是,在构造函数完成后,我期待反序列化器 将 Key=1 的默认值(在构造函数中设置)替换为从 JSON 字符串反序列化的值 2。 问题是反序列化对象“输出”的属性 Key 的值是 1 而不是 2。

为什么会这样? 反序列化器在构造对象后会跳过非空属性吗?

在线示例(.NET Fiddle)

https://dotnetfiddle.net/P5GguD

【问题讨论】:

  • 为什么不用MyClass output = JsonConvert.DeserializeObject&lt;MyClass&gt;(json);
  • 看起来serializer.Deserialize 没有设置显式属性。如果从构造函数中删除Key = 1;,它将显示0。不知道为什么..
  • JsonTextReader 在那里实际上不起作用,该类未反序列化,因此您使用构造函数中设置的值创建一个新的类对象。使用var textStream = new MemoryStream(Encoding.UTF8.GetBytes(jsonMC));(UTF-8 是默认值,而不是 UTF16-LE)。或者明确指定编码:using (var sr = new StreamReader(textStream, Encoding.Unicode))
  • 请注意,在反序列化中,您可以指定,例如,[DefaultValue(1)][JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] public int Key { get; set; }。如果 JSON 字符串中缺少 Key 属性,则将设置默认值 (1)。 -> 在上一条评论中,jsonMC 是复制/粘贴错误,您的原始字符串命名为 json :)

标签: c# json.net


【解决方案1】:

您错过了在 StreamReader 中提供编码类型。结果流没有正确构建。

using (var sr = new StreamReader(textStream,Encoding.Unicode)) //Provide encoding as Unicode
{
    using (var jr = new JsonTextReader(sr))
    {
        var serializer = new JsonSerializer();
        output = serializer.Deserialize<MyClass>(jr);
    }
}

【讨论】:

  • 我很震惊我在演示中犯了这个错误。但是原始的现实生活中的代码,没有编码错误。如果我从构造函数中删除 LoadDefault() 调用,该类将被正确反序列化并填充来自 JSON 的值。所以那里有一个错误,在创建演示时,我不小心生成了相同的行为,但有一个不同的错误。所以你的回答对我的问题是正确的。但是我只是注意到我在原始代码中继续存在问题。
【解决方案2】:

直接反序列化了,为什么要在StreamReader中设置呢?可以直接使用serialize返回的JSON字符串值进行反序列化。

var mc = new MyClass(){Key = 2};
var json = JsonConvert.SerializeObject(mc);

Console.WriteLine("Serialized Key is: " + mc.Key);

MyClass output = JsonConvert.DeserializeObject<MyClass>(json);
        
Console.WriteLine("De-serialized Key is: " + output.Key);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-09
    • 1970-01-01
    • 2021-05-21
    • 2013-03-22
    • 1970-01-01
    • 2015-03-17
    • 1970-01-01
    相关资源
    最近更新 更多