Json.NET反序列化和属性设置器的副作用

时间:2019-04-05 13:00:09

标签: c# json json.net

当我遇到一个有副作用的属性设置器时,出现了一个问题(对Separation of concerns来说这是不好的设计)。

以下问题是理论上的问题,从理论上讲,应该通过消除属性设置器的副作用来解决此问题。

但是如果不能修改DTO类,是否有任何机制可以防止使用Json.NET时JSON反序列化引起副作用?

问题场景:

下面显示的是Myclass和两个JSON代码段。

调用JsonConvert.Deserialize<MyClass>(json)时,根据JSON属性的顺序,会得到不同的结果。

数据传输类别:

public class MyClass
{
    private string _evilField1;
    public string EvilField1
    {
        get
        {
            return _evilField1;
        }
        set
        {
            _evilField1 = value;
            Info = "EvilField1.Set messed Info";
        }
    }

    private string _evilField2;
    public string EvilField2
    {
        get
        {
            return _evilField2;
        }
        set
        {
            _evilField2 = value;
            Info = "EvilField2.Set messed Info";
        }
    }

    public string Info { get; set; }
}

输入数据

{
  "EvilField1": "Foo",
  "EvilField2": "Foo",
  "Info": "Initial value"
}

{
  "EvilField1": "Foo",
  "Info": "Initial value",
  "EvilField2": "Foo"
}

反序列化数据

第一个JSON不会触发副作用,但是第二个JSON会带来讨厌的输出:

{
  "EvilField1": "Foo",
  "Info": "Initial value",
  "EvilField2": "Foo"
}

{
  "EvilField1": "Foo",
  "EvilField2": "Foo",
  "Info": "EvilField2.Set messed Info"
}

1 个答案:

答案 0 :(得分:3)

您可以为有问题的类创建自定义JsonConverter。这样一来,您就可以以所需的任何方式填充它,以解决有害的副作用。

public class MyClassConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(MyClass);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null) return null;

        JObject obj = JObject.Load(reader);

        // Populate the "Info" field last so it will not be overwritten
        return new MyClass
        {
            EvilField1 = (string)obj["EvilField1"],
            EvilField2 = (string)obj["EvilField2"],
            Info = (string)obj["Info"]
        };
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

要使用转换器,您可以添加有问题的类的[JsonConverter]属性...

[JsonConverter(typeof(MyClassConverter))]
public class MyClass
{
    ...
}

...,也可以通过设置将转换器的实例传递给DerserializeObject()方法:

var settings = new JsonSerializerSettings();
settings.Converters.Add(new MyClassConverter());

var obj = JsonConvert.DeserializeObject<MyClass>(json, settings);

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