【问题标题】:Custom JsonConverter not called for nested property嵌套属性不调用自定义 JsonConverter
【发布时间】:2019-08-02 19:09:36
【问题描述】:

我有一个 Employee 类,其中 Manager 属性本身是 Employee 类型

public class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Employee Manager { get; set; }
    public IList<string> Roles { get; set; }
}

我想为 Employee 类型创建一个自定义的 JsonConverter。

public class TestJsonConverter : JsonConverter
{
    public TestJsonConverter()
    {
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        JToken t = JToken.FromObject(value);
        if (t.Type != JTokenType.Object)
        {
            t.WriteTo(writer);
        }
        else
        {
            JObject o = (JObject)t;
            IList<string> propertyNames = o.Properties().Select(p => p.Name).ToList();
            o.AddFirst(new JProperty("Keys", new JArray(propertyNames)));
            o.WriteTo(writer);
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
    }

    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(Employee));
    }

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

ContractResolver 是

class ContractResolver : DefaultContractResolver
{
    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        JsonObjectContract contract = base.CreateObjectContract(objectType);
        if (objectType == typeof(Employee))
        {
            contract.Converter = new TestJsonConverter();
        }
        return contract;
    }
}

当我尝试序列化 Employee 对象时,仅为顶级 Employee 对象调用自定义 JsonConverter,而不是为同样属于 Employee 类型的嵌套 Manager 属性调用:

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new ContractResolver();
string json = JsonConvert.SerializeObject(employee, Formatting.Indented, settings);

【问题讨论】:

标签: c# json json.net


【解决方案1】:

我认为您遇到了相同的问题 Custom JsonConverter WriteJson Does Not Alter Serialization of Sub-properties:

您的转换器未应用于您的子对象的原因是因为 JToken.FromObject() 在内部使用了一个新的序列化程序实例,它不知道您的转换器。

提供的解决方案应该适合您的情况。

【讨论】:

    【解决方案2】:

    所以JsonConverter 运行一次,从根节点开始。 您将需要导航此 JSON 对象树并自行更新。

    不确定这是您想要实现的目标,但我自己尝试过,您可以决定这是否适合您。

    public class TestJsonConverter : JsonConverter
    {
        public TestJsonConverter()
        {
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            JToken t = JToken.FromObject(value);
            if (t.Type != JTokenType.Object)
            {
                t.WriteTo(writer);
            }
            else
            {
                JObject root = (JObject)t;
                var stack = new Stack<JObject>();
                stack.Push(root);
                while (stack.Any())
                {
                    var current = stack.Pop();
                    var propertyNames = current.Properties().Select(p => p.Name).ToArray();
                    current.AddFirst(new JProperty("Keys", new JArray(propertyNames)));
    
                    var nestedObjects = current.Properties().Where(p => p.Value.Type == JTokenType.Object).ToArray();
                    foreach (var nestedObj in nestedObjects)
                    {
                        stack.Push((JObject)nestedObj.Value);
                    }
                }
    
                root.WriteTo(writer);
            }
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
        }
    
        public override bool CanConvert(Type objectType)
        {
            return (objectType == typeof(Employee));
        }
    
        public override bool CanRead
        {
            get { return false; }
        }
    }
    

    【讨论】:

    • 感谢您的回复。我还是有些困惑。当我在 Manager 属性上使用属性 [JsonConverter(typeof(TestJsonConverter))] 时,它可以工作。当我提到链接stackoverflow.com/questions/27332258/… 时,它说 IContractResolver 可用于实现与 JsonConverter 属性相同的结果。不知道我在这里错过了什么。
    猜你喜欢
    • 2017-09-08
    • 1970-01-01
    • 1970-01-01
    • 2020-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    相关资源
    最近更新 更多