如何配置 JSON.net 反序列化器以跟踪丢失的属性?

时间:2023-04-25
本文介绍了如何配置 JSON.net 反序列化器以跟踪丢失的属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

示例类:

public class ClassA
{
    public int Id { get; set; }
    public string SomeString { get; set; }
    public int? SomeInt { get; set; }
}

默认反序列化器:

var myObject = JsonConvert.DeserializeObject<ClassA>(str);

为两个不同的输入创建相同的对象

Create the same object for two different inputs

{"Id":5}

{"Id":5,"SomeString":null,"SomeInt":null} 

如何跟踪反序列化过程中丢失的属性并保持相同的行为?有没有办法覆盖一些 JSON.net 序列化方法(例如 DefaultContractResolver 类方法)来实现这一点.例如:

How can I track properties that were missing during deserialization process and preserve the same behavior? Is there a way to override some of JSON.net serializer methods (e.g. DefaultContractResolver class methods) to achive this. For example:

List<string> missingProps;
var myObject = JsonConvert.DeserializeObject<ClassA>(str, settings, missingProps);

第一个输入列表应包含缺失属性的名称(SomeString"、SomeInt"),第二个输入应为空.反序列化的对象保持不变.

For the first input list should contains the names of the missing properties ("SomeString", "SomeInt") and for second input it should be empty. Deserialized object remains the same.

推荐答案

在反序列化过程中找到空/未定义令牌的另一种方法是编写自定义 JsonConverter ,这里是自定义转换器的示例它可以报告省略的标记(例如 "{ 'Id':5 }")和空标记(例如 {"Id":5,"SomeString":null,"SomeInt":空})

Another way to find null/undefined tokens during De-serialization is to write a custom JsonConverter , Here is an example of custom converter which can report both omitted tokens (e.g. "{ 'Id':5 }") and null tokens (e.g {"Id":5,"SomeString":null,"SomeInt":null})

public class NullReportConverter : JsonConverter
{
    private readonly List<PropertyInfo> _nullproperties=new List<PropertyInfo>();
    public bool ReportDefinedNullTokens { get; set; }

    public IEnumerable<PropertyInfo> NullProperties
    {
        get { return _nullproperties; }
    }

    public void Clear()
    {
        _nullproperties.Clear();
    }

    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        existingValue = existingValue ?? Activator.CreateInstance(objectType, true);

        var jObject = JObject.Load(reader);
        var properties =
            objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        foreach (var property in properties)
        {
            var jToken = jObject[property.Name];
            if (jToken == null)
            {
                _nullproperties.Add(property);
                continue;
            }

            var value = jToken.ToObject(property.PropertyType);
            if(ReportDefinedNullTokens && value ==null)
                _nullproperties.Add(property);

            property.SetValue(existingValue, value, null);
        }

        return existingValue;
    }

    //NOTE: we can omit writer part if we only want to use the converter for deserializing
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var objectType = value.GetType();
        var properties =
            objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        writer.WriteStartObject();
        foreach (var property in properties)
        {
            var propertyValue = property.GetValue(value, null);
            writer.WritePropertyName(property.Name);
            serializer.Serialize(writer, propertyValue);
        }

        writer.WriteEndObject();
    }
}

注意:如果我们不需要将 Writer 部分用于序列化对象,我们可以省略它.

用法示例:

class Foo
{
    public int Id { get; set; }
    public string SomeString { get; set; }
    public int? SomeInt { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var nullConverter=new NullReportConverter();

        Console.WriteLine("Pass 1");
        var obj0 = JsonConvert.DeserializeObject<Foo>("{"Id":5, "Id":5}", nullConverter);
        foreach(var p in nullConverter.NullProperties)
            Console.WriteLine(p);

        nullConverter.Clear();

        Console.WriteLine("Pass2");
        var obj1 = JsonConvert.DeserializeObject<Foo>("{"Id":5,"SomeString":null,"SomeInt":null}" , nullConverter);
        foreach (var p in nullConverter.NullProperties)
            Console.WriteLine(p);

        nullConverter.Clear();

        nullConverter.ReportDefinedNullTokens = true;
        Console.WriteLine("Pass3");
        var obj2 = JsonConvert.DeserializeObject<Foo>("{"Id":5,"SomeString":null,"SomeInt":null}", nullConverter);
        foreach (var p in nullConverter.NullProperties)
            Console.WriteLine(p);
    }
}

这篇关于如何配置 JSON.net 反序列化器以跟踪丢失的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:在没有属性的类上全局使用 JsonConverter 下一篇:使用 Json.NET 的 Pascal 案例动态属性

相关文章