Json.NET不会使用自定义getter和不可变类型反序列化属性

时间:2019-10-17 10:43:03

标签: c# json serialization json.net deserialization

我正在使用Newtonsoft.Json(又称Json.Net)对我的课程进行序列化:

public class ClassWithCustomProperty
{
    private ImmutableValue value;
    public ImmutableValue Value
    {
        get => value = (value ?? new ImmutableValue(0));
        set => this.value = value;
    }
}

public class ImmutableValue
{
    public readonly int Value;
    public ImmutableValue(int value) => Value = value;
}

但是当我序列化和反序列化对象时,我没有收到期望的值:

public static class Program
{
    public static void Main()
    {
        var json = JsonConvert.SerializeObject(new ClassWithCustomProperty
        {
            Value = new ImmutableValue(42)
        });
        // JSON is {"Value": {"Value": 42}} as expected

        var obj = JsonConvert.DeserializeObject<ClassWithCustomProperty>(json);
        Console.WriteLine(obj.Value?.Value); 
        // But after deserialization obj.Value.Value is 0, instead of 42
    }
}

出什么问题了,或者如何改变这种行为?

我注意到,如果我自己对ImmutableValue进行序列化和反序列化,则可以正常工作:

var json = JsonConvert.SerializeObject(new ImmutableValue(42));
var obj = JsonConvert.DeserializeObject<ImmutableValue>(json);
Console.WriteLine(obj.Value);  // 42

1 个答案:

答案 0 :(得分:3)

罪魁祸首是您的ClassWithCustomProperty类中的这一行:

    get => value = (value ?? new ImmutableValue(0));

Json.Net的默认行为是重用现有对象,而不是替换它们。因此,当需要对ImmutableValue上的ClassWithCustomProperty进行反序列化时,串行器首先检查是否存在现有值。 (上面的)访问器发现没有访问器,因此它创建了一个值为0的访问器,并将其返回给序列化器。然后,串行器尝试重用此现有对象,但是由于它是只读的,因此无法在其上设置值42。因此该值保持为零。

有一个ObjectCreationHandling设置可用于更改此行为。如果将其设置为Replace,它将按照您想要的方式工作。尝试这样:

var settings = new JsonSerializerSettings 
{ 
    ObjectCreationHandling = ObjectCreationHandling.Replace 
};
var obj = JsonConvert.DeserializeObject<ClassWithCustomProperty>(json, settings);

提琴:https://dotnetfiddle.net/UVDMsL