使用 json.net 的对象属性的条件序列化/反序列化

本文关键字:序列化 反序列化 条件 对象 json net 使用 属性 | 更新日期: 2023-09-27 18:35:17

我有一个场景,其中的类定义如下:

class MyObject
{
    public DataDictionary MyObjectData { get; set; }
    public bool ShouldSerializeMyObjectData() { return true; }
    public bool ShouldDeserializeMyObjectData() { return false; }
}

当我尝试使用 JSON.net 序列化/反序列化该类时,它会考虑 ShouldSerialize,而不是 ShouldDeserialize。

根据文档,我猜两者都应该以相同的方式工作。有什么我应该知道的吗?更一般地说,我应该如何处理我想序列化属性但不反序列化它的情况?

如果这很重要,我正在使用Json.NET 8.0

感谢您的帮助。

使用 json.net 的对象属性的条件序列化/反序列化

对您的问题的简短回答是,即使ShouldSerialize{PropertyName}()实现自动检查ShouldDeserialize{PropertyName}(),当前也没有实现。 下面是更长的答案和解决方法。

Json.NET 在内部使用该类 JsonProperty 来定义如何将 JSON 属性映射到 .NET 成员或构造函数参数的协定。 它有两个谓词属性,ShouldSerializeShouldDeserialize,当非 null 时,分别阻止属性被序列化和反序列化。 初始化每个JsonPropertyContractResolver的工作。 对于每个属性{PropertyName},Json.NET 的默认合约解析器会自动检查是否存在public bool ShouldSerialize{PropertyName}()方法。 如果存在这样的方法,它会在ShouldSerialize谓词中添加对它的调用,从而在方法返回 false 时禁止序列化。 之所以实现这一点,是因为通过方法ShouldSerialize{PropertyName}()控制属性序列化是 XmlSerializer 等支持的标准模式。 有关更多背景信息,请参阅相关的 Json.NET 发行说明。

例如,在下面的类中,除非MyObjectData.Count > 0,否则将禁止MyObjectData的序列化:

class MyObject
{
    public DataDictionary MyObjectData { get; set; }
    public bool ShouldSerializeMyObjectData() { return MyObjectData != null && MyObjectData.Count > 0; }
}

JsonProperty.ShouldDeserialize ,但是,它永远不会由默认合约解析器设置。 这可能是因为没有等同于ShouldSerialize{PropertyName}()的标准反序列化模式,因此 Newtonsoft 从未收到过实现这种模式的任何请求。 尽管如此,正如您已经注意到的那样,存在支持这种模式的基础结构,因此应用程序可以创建执行此操作的自定义协定解析器。 事实上,Json.NET 在自己的测试套件中有一个这样的合约解析器的例子:

public class ShouldDeserializeContractResolver : DefaultContractResolver
{
    public static new readonly ShouldDeserializeContractResolver Instance = new ShouldDeserializeContractResolver();
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        MethodInfo shouldDeserializeMethodInfo = member.DeclaringType.GetMethod("ShouldDeserialize" + member.Name);
        if (shouldDeserializeMethodInfo != null)
        {
            property.ShouldDeserialize = o => { return (bool)shouldDeserializeMethodInfo.Invoke(o, null); };
        }
        return property;
    }
}
public class ShouldDeserializeTestClass
{
    [JsonExtensionData]
    public IDictionary<string, JToken> ExtensionData { get; set; }
    public bool HasName { get; set; }
    public string Name { get; set; }
    public bool ShouldDeserializeName()
    {
        return HasName;
    }
}

如果要有条件地禁止属性的反序列化(即使存在于 JSON 中),也可以使用此协定解析程序。

笔记:

  • 如果您确实使用自定义协定解析程序,则应缓存并重用它以获得最佳性能。

  • 在反序列化属性值之前调用JsonProperty.ShouldDeserialize。 如果返回 true,则跳过该属性,无法检查该属性的内容。 因此,它不能用于实现基于该值的自定义筛选。

  • JSON
  • 对象由 JSON 标准定义为一组无序的名称/值对。 因此,假定已读入其他属性的ShouldDeserialize方法可能很脆弱。

    相反,如果要跳过基于一个属性的值对另一个属性的反序列化,请考虑在所有属性反序列化后使用[OnDeserialized]回调并清除其中不需要的值。