Can I serialize nested properties to my class in one operation with Json.net?

前端 未结 3 737
再見小時候
再見小時候 2020-11-27 22:40

Lets say I have a model like:

public class MyModel
{
    public string Name { get; set; }
    public string[] Size { get; set; }
    public string Weight { g         


        
3条回答
  •  隐瞒了意图╮
    2020-11-27 23:23

    This should work:

    public class MyModelJsonConverter : JsonConverter
    {
        public override bool CanRead
        {
            get { return true; }
        }
    
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(MyModel);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (objectType != typeof(MyModel))
            {
                throw new ArgumentException("objectType");
            }
    
            switch (reader.TokenType)
            {
                case JsonToken.Null:
                {
                    return null;
                }
                case JsonToken.StartObject:
                {
                    reader.Read();
                    break;
                }
                default:
                {
                    throw new JsonSerializationException();
                }
            }
    
            var result = new MyModel();
            bool inDetails = false;
    
            while (reader.TokenType == JsonToken.PropertyName)
            {
                string propertyName = reader.Value.ToString();
                if (string.Equals("name", propertyName, StringComparison.OrdinalIgnoreCase))
                {
                    reader.Read();
                    result.Name = serializer.Deserialize(reader);
                }
                else if (string.Equals("size", propertyName, StringComparison.OrdinalIgnoreCase))
                {
                    if (!inDetails)
                    {
                        throw new JsonSerializationException();
                    }
    
                    reader.Read();
                    result.Size = serializer.Deserialize(reader);
                }
                else if (string.Equals("weight", propertyName, StringComparison.OrdinalIgnoreCase))
                {
                    if (!inDetails)
                    {
                        throw new JsonSerializationException();
                    }
    
                    reader.Read();
                    result.Weight = serializer.Deserialize(reader);
                }
                else if (string.Equals("details", propertyName, StringComparison.OrdinalIgnoreCase))
                {
                    reader.Read();
    
                    if (reader.TokenType != JsonToken.StartObject)
                    {
                        throw new JsonSerializationException();
                    }
    
                    inDetails = true;
                }
                else
                {
                    reader.Skip();
                }
    
                reader.Read();
            }
            if (inDetails)
            {
                if (reader.TokenType != JsonToken.EndObject)
                {
                    throw new JsonSerializationException();
                }
    
                reader.Read();
            }
    
            return result;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value == null)
            {
                writer.WriteNull();
                return;
            }
    
            var model = value as MyModel;
            if (model == null) throw new JsonSerializationException();
    
            writer.WriteStartObject();
            writer.WritePropertyName("name");
            writer.WriteValue(model.Name);
            writer.WritePropertyName("details");
            writer.WriteStartObject();
            writer.WritePropertyName("size");
            serializer.Serialize(writer, model.Size);
            writer.WritePropertyName("weight");
            writer.WriteValue(model.Weight);
            writer.WriteEndObject();
            writer.WriteEndObject();
        }
    }
    
    [JsonConverter(typeof(MyModelJsonConverter))]
    public class MyModel
    {
        public string Name { get; set; }
        public string[] Size { get; set; }
        public string Weight { get; set; }
    }
    

    With the attribute on the class, using it is as easy as:

    var model = new MyModel
    {
        Name = "widget",
        Size = new[] { "XL", "M", "S" },
        Weight = "heavy"
    };
    
    string output = JsonConvert.SerializeObject(model);
    // {"name":"widget","details":{"size":["XL","M","S"],"weight":"heavy"}}
    
    var model2 = JsonConvert.DeserializeObject(output);
    /*
    {
        Name = "widget",
        Size = [ "XL", "M", "S" ],
        Weight = "heavy"
    }
    */
    

提交回复
热议问题