Deserialize two values into the same property

后端 未结 2 1842
被撕碎了的回忆
被撕碎了的回忆 2021-01-25 08:55

I have a client which can call two different versions of a service.

One service only sends a single value:

{
  \"value\" : { ... }
}

T

2条回答
  •  既然无缘
    2021-01-25 09:30

    To make a custom JsonConverter that has special processing for a few properties of a type but uses default processing for the remainder, you can load the JSON into a JObject, detach and process the custom properties, then populate the remainder from the JObject with JsonSerializer.Populate(), like so:

    class MyValuesConverter : CustomPropertyConverterBase
    {
        protected override void ProcessCustomProperties(JObject obj, MyValues value, JsonSerializer serializer)
        {
            // Remove the value property for manual deserialization, and deserialize
            var jValue = obj.GetValue("value", StringComparison.OrdinalIgnoreCase).RemoveFromLowestPossibleParent();
            if (jValue != null)
            {
                (value.Values = value.Values ?? new List()).Clear();
                value.Values.Add(jValue.ToObject(serializer));
            }
        }
    }
    
    public abstract class CustomPropertyConverterBase : JsonConverter where T : class
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(T).IsAssignableFrom(objectType);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
            var jObj = JObject.Load(reader);
            var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType);
            var value = existingValue as T ?? (T)contract.DefaultCreator();
    
            ProcessCustomProperties(jObj, value, serializer);
    
            // Populate the remaining properties.
            using (var subReader = jObj.CreateReader())
            {
                serializer.Populate(subReader, value);
            }
    
            return value;
        }
    
        protected abstract void ProcessCustomProperties(JObject obj, T value, JsonSerializer serializer);
    
        public override bool CanWrite { get { return false; } }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    
    public static class JsonExtensions
    {
        public static JToken RemoveFromLowestPossibleParent(this JToken node)
        {
            if (node == null)
                return null;
            var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
            if (contained != null)
                contained.Remove();
            // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
            if (node.Parent is JProperty)
                ((JProperty)node.Parent).Value = null;
            return node;
        }
    }
    

提交回复
热议问题