Deserialize JSON to 2 different models

前端 未结 9 1216
眼角桃花
眼角桃花 2021-02-06 23:42

Does Newtonsoft.JSON library have a simple way I can automatically deserialize JSON into 2 different Models/classes?

For example I get the JSON:

[{
  \"g         


        
相关标签:
9条回答
  • 2021-02-06 23:53

    In your models, The name properties need to be strings, instead of integers. After correcting it.

    You can use Tuple class

    string json = @"[{'guardian_id':'1453','guardian_name':'Foo Bar','patient_id':'938','patient_name':'Foo Bar'}]";
    
    var combination = new Tuple<List<Guardian>, List<Patient>>(JsonConvert.DeserializeObject<List<Guardian>>(json), JsonConvert.DeserializeObject<List<Patient>>(json));
    
    0 讨论(0)
  • 2021-02-06 23:57

    It can't be done with 1 call with the types that you show. You can try using the generic <T> approach for each type, also you'll need to use arrays or lists for the return type because the source JSON is an array:

    var guardians = JsonConvert.DeserializeObject<Guardian[]>(response.Content);
    var patients = JsonConvert.DeserializeObject<Patient[]>(response.Content);
    

    And then combine the two if you need them to be paired. E.g. if you are sure that you always have just one of each:

    var pair = new Pair(guardians[0], patients[0]);
    
    0 讨论(0)
  • 2021-02-06 23:58

    One another approach would be creating class that matches JSON format, i.e. class with four properties with corresponding names. Then, deserialize JSON into that class and then use it in your code (set properties of objects with values from JSON, pass deserialized object to constructor of another class).

    0 讨论(0)
  • 2021-02-07 00:04

    You could make a type to house the two subobjects:

    [JsonConverter(typeof(GuardianPatientConverter))]
    class GuardianPatient
    {
        public Guardian Guardian { get; set; }
        public Patient Patient { get; set; }
    }
    

    And then create a JSON converter to handle the JSON:

    class GuardianPatientConverter : JsonConverter
    {
        public override bool CanRead
        {
            get { return true; }
        }
    
        public override bool CanWrite
        {
            get { return false; }
        }
    
        public override bool CanConvert(Type objectType)
        {
            return typeof(GuardianPatient) == objectType;
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
            {
                return null;
            }
    
            var jObject = JObject.Load(reader);
            var guardian = new Guardian();
            var patient = new Patient();
            serializer.Populate(jObject.CreateReader(), guardian);
            serializer.Populate(jObject.CreateReader(), patient);
            return new GuardianPatient()
            {
                Guardian = guardian,
                Patient = patient
            };
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    And then you can use it like so:

    var json = "[{\"guardian_id\":\"1453\",\"guardian_name\":\"Foo Bar\",\"patient_id\":\"938\",\"patient_name\":\"Foo Bar\",}]";
    var objects = JsonConvert.DeserializeObject<IEnumerable<GuardianPatient>>(json);
    

    and if you want it as an array of pairs:

    var objects = JsonConvert.DeserializeObject<IEnumerable<GuardianPatient>>(json)
        .Select(o => new Pair(o.Guardian, o.Patient))
        .ToArray();
    

    This won't make it any faster, but I suspect you're looking for an easier way to work with the JSON.

    0 讨论(0)
  • 2021-02-07 00:06

    Not in one call, and it seems the data is an array, so you need a little more work.

    Zip is the key method here to join the two separate object lists:

    Guardian[] guardians = JsonConvert.DeserializeObject<Guardian[]>(response.Content);
    Patient[] patients = JsonConvert.DeserializeObject<Patient[]>(response.Content);
    
    var combined = guardians.Zip(patients, (g, p) => Tuple.Create(g, p)).ToList();
    

    It would be far more easier to just read the JSON at once, it a single object.

    0 讨论(0)
  • 2021-02-07 00:07

    First off, your models are slightly incorrect. The name properties need to be strings, instead of integers:

    class Guardian
    {
    
        [JsonProperty(PropertyName = "guardian_id")]
        public int ID { get; set; }
    
        [JsonProperty(PropertyName = "guardian_name")]
        public string Name { get; set; }            // <-- This
    }
    
    
    class Patient
    {
    
        [JsonProperty(PropertyName = "patient_id")]
        public int ID { get; set; }
    
        [JsonProperty(PropertyName = "patient_name")]
        public string Name { get; set; }            // <-- This
    }
    

    Once you've corrected that, you can deserialize the JSON string into two lists of different types. In your case, List<Guardian> and List<Patient> respectively:

    string json = @"[{'guardian_id':'1453','guardian_name':'Foo Bar','patient_id':'938','patient_name':'Foo Bar'}]";
    var guardians = JsonConvert.DeserializeObject<List<Guardian>>(json);
    var patients = JsonConvert.DeserializeObject<List<Patient>>(json);
    
    0 讨论(0)
提交回复
热议问题