将JSON反序列化为2个不同的模型

时间:2018-04-04 08:06:44

标签: c# json json.net

Newtonsoft.JSON库是否有一种简单的方法可以自动将JSON反序列化为2个不同的模型/类?

例如,我得到了JSON:

[{
  "guardian_id": "1453",
  "guardian_name": "Foo Bar",
  "patient_id": "938",
  "patient_name": "Foo Bar",
}]

我需要将其反序列化为以下模型:

class Guardian {

  [JsonProperty(PropertyName = "guardian_id")]
  public int ID { get; set; }

  [JsonProperty(PropertyName = "guardian_name")]
  public int Name { get; set; }
}


class Patient {

  [JsonProperty(PropertyName = "patient_id")]
  public int ID { get; set; }

  [JsonProperty(PropertyName = "patient_name")]
  public int Name { get; set; }
}

是否有一种简单的方法可以将此JSON反序列化为2个模型,而无需迭代JSON?也许JSON属性id会起作用吗?

Pair<Guardian, Patient> pair = JsonConvert.DeserializeObject(response.Content);

9 个答案:

答案 0 :(得分:27)

首先,您的模型稍有不正确。名称属性需要是字符串,而不是整数:

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
}

一旦您更正了这一点,就可以将JSON字符串反序列化为两个不同类型的列表。在您的情况下,分别为List<Guardian>List<Patient>

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);

答案 1 :(得分:10)

你想用1次调用来做,你需要创建一个与JSON匹配的类。然后,该类可以根据需要返回GuardianPatient个对象。此外,您还需要使用数组或列表作为返回类型,因为源JSON 是一个数组。

要创建的课程:

public class Pair
{
    public Pair()
    {
        Guardian = new Guardian();
        Patient = new Patient();
    }

    [JsonIgnore]
    public Guardian Guardian { get; set; }

    [JsonIgnore]
    public Patient Patient { get; set; }

    [JsonProperty(PropertyName = "guardian_id")]
    public int GuardianID
    {
        get { return Guardian.ID; }
        set { Guardian.ID = value; }
    }

    [JsonProperty(PropertyName = "guardian_name")]
    public string GuardianName
    {
        get { return Guardian.Name; }
        set { Guardian.Name = value; }
    }

    [JsonProperty(PropertyName = "patient_id")]
    public int PatientID
    {
        get { return Patient.ID; }
        set { Patient.ID = value; }
    }

    [JsonProperty(PropertyName = "patient_name")]
    public string PatientName
    {
        get { return Patient.Name; }
        set { Patient.Name = value; }
    }
}

以及如何使用它:

var pairs = JsonConvert.DeserializeObject<Pair[]>(response.Content);

if (pairs.Any())
{
    var pair = pairs[0];
    Console.WriteLine(pair.Guardian.Name);
    Console.WriteLine(pair.Patient.Name);
}

答案 2 :(得分:9)

不是在一个电话中,似乎数据是一个数组,所以你需要多做一些工作。

Zip是加入两个单独对象列表的关键方法:

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();

一次只读一个JSON会更容易,它只是一个对象。

答案 3 :(得分:8)

使用您显示的类型进行1次调用无法完成。您可以尝试对每种类型使用通用<T>方法,您还需要使用数组或列表作为返回类型,因为源JSON 是一个数组:

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

如果你需要将它们配对,然后将两者结合起来。例如。如果你确定你总是只有一个:

var pair = new Pair(guardians[0], patients[0]);

答案 4 :(得分:1)

另一种方法是创建与JSON格式匹配的类,即具有四个具有相应名称的属性的类。然后,将JSON反序列化到该类中,然后在代码中使用它(使用JSON值设置对象的属性,将反序列化的对象传递给另一个类的构造函数)。

答案 5 :(得分:1)

您可以创建一个类型来容纳两个子对象:

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

然后创建一个JSON转换器来处理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();
    }
}

然后你可以这样使用它:

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

如果你想把它作为一对数组:

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

这不会让它变得更快,但我怀疑你正在寻找一种更简单的方法来使用JSON。

答案 6 :(得分:0)

在模型中,名称属性需要是字符串,而不是整数。纠正后。

您可以使用Tuple

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));

答案 7 :(得分:0)

    static void Main(string[] args)
    {
        string json = JsonConvert.SerializeObject(new[] 
        {
            new
            {
                guardian_id = "1453",
                guardian_name = "Foo Bar",
                patient_id = "938",
                patient_name = "Bar Foo",
            }
        });

        Guardian[] guardians = JsonConvert.DeserializeObject<Guardian[]>(json);
        Patient[] patients = JsonConvert.DeserializeObject<Patient[]>(json);
    }

答案 8 :(得分:-1)

由于两个对象都是相同的,所以只拥有一个基类的ID / Name结构会不会更有意义?如果需要同时发送所有数据,则可以重新构建数据并使用数据传输对象模式。 JSON对象将变为

[{
  "guardian": {
    "id": "1453",
    "name": "Foo Bar"
  },
  "patient": {
    "id" : "938",
    "name": "Foo Bar"
  }
}]

您的相应数据对象将是:

public class Record {
  public int id { get; set; } // or string.  I'm not sure which would be more appropriate
  public string name { get; set;}
}

public class RecordDto {
  public Record guardian { get; set; }
  public Record patient { get; set; }
}

您的API会收到

List<RecordDto>

参数(因为你传递了一个对象数组)。