【问题标题】:Deserialize two slightly different JSON strings (same structure, different names) to the same class将两个略有不同的 JSON 字符串(结构相同,名称不同)反序列化为同一个类
【发布时间】:2016-04-27 16:16:17
【问题描述】:

简而言之,我的问题是:我需要将两个大的 JSON 字符串反序列化为一个类,但字符串略有不同。这是第一个:

 {  
  "persons": [  
    {  
      "age":30,
      "name":"david",
      "hobbies": [  
        {  
          "name":"tennis",
          "hours":5
        },
       {  
         "name":"football",
         "hours":10
       }
     ]
   },
   {  
     "name":"adam",
     "age":23,
     "hobbies":[]
   }
 ]   
}  

还有一个:

{  
  "person": [  
    {  
      "age":25,
      "name":"dave",
      "hobbies":[  
        {  
          "name":"Basketball",
          "hours":5
        },
        {  
          "name":"football",
          "hours":10
        }
      ]
    },
    {  
      "name":"Steve",
      "age":28,
      "hobbies": []
    }
  ]
}

您可以看到一次是“Persons”,另一次是“Person”。有什么简单的解决方案吗?我正在考虑在我的课堂上创建两个列表

List<Person> person;
List<Person> persons;

在反序列化之后以某种方式手动组合。但必须有一个更简单的方法。

顺便说一句,这不是我需要反序列化的确切代码。我只是想让主要思想尽可能简单。

【问题讨论】:

    标签: c# json.net deserialization


    【解决方案1】:

    一个简单的解决方案是在您的类中使用单个列表,然后添加一个替代设置器,该设置器具有引用相同列表的另一个名称。您甚至可以将其设为私有,只要您使用 [JsonProperty] 属性对其进行装饰即可。这样你的类的公共接口看起来很正常,但它仍然可以使用两个 JSON 属性名称。

    public class RootObject
    {
        [JsonProperty("persons")]
        public List<Person> People { get; set; }
    
        // This is visible to Json.Net and references the real list
        [JsonProperty("person")]
        private List<Person> Person
        {
            set { People = value; }
        }
    }
    
    public class Person
    {
        [JsonProperty("name")]
        public string Name { get; set; }
    
        [JsonProperty("age")]
        public int Age { get; set; }
    
        [JsonProperty("hobbies")]
        public List<Hobby> Hobbies { get; set; }
    }
    
    public class Hobby
    {
        [JsonProperty("name")]
        public string Name { get; set; }
    
        [JsonProperty("hours")]
        public int Hours { get; set; }
    
    }
    

    小提琴:https://dotnetfiddle.net/9Dw48J

    编辑

    解决您的 cmets:PopulateObject 可用于使用来自 JSON 的数据盲目地扩充现有对象,但它不会进行您正在寻找的那种合并。您似乎正在寻找一种方法来按姓名(可能还有年龄?)匹配人,然后结合这些人的爱好。为此,您需要编写自己的逻辑。我建议将每个列表反序列化为 RootObject 类的单独实例,然后在后处理步骤中合并数据。您可以在 RootObject 类上创建一个方法,该方法将接受另一个 RootObject 进行合并。也许是这样的:

    public class RootObject
    {
        ...
    
        public void MergeWith(RootObject other)
        {
            if (other.People == null) return;
            if (People == null) People = new List<Person>();
            foreach (Person person in other.People)
            {
                // You may need to make changes here--
                // How do you determine whether two people are the same?
                Person existingPerson = People.FirstOrDefault(p => p.Name == person.Name && 
                                                                   p.Age == person.Age);
                if (existingPerson != null)
                {
                    existingPerson.MergeWith(person);
                }
                else
                {
                    People.Add(person);
                }
            }
        }
    }
    

    Person 类...

    public class Person
    {
        ...
    
        public void MergeWith(Person other)
        {
            if (other.Hobbies == null) return;
            if (Hobbies == null) Hobbies = new List<Hobby>();
            foreach (Hobby hobby in other.Hobbies)
            {
                Hobby existingHobby = Hobbies.FirstOrDefault(h => h.Name == hobby.Name);
                if (existingHobby != null)
                {
                    // You may need to make changes here--
                    // What do you do if two hobbies have the same name but different hours?
                    existingHobby.Hours += hobby.Hours;
                }
                else
                {
                    Hobbies.Add(hobby);
                }
            }
        }
    }
    

    要反序列化和合并,你可以这样做:

    var firstObj = JsonConvert.DeserializeObject<RootObject>(firstJson);
    var secondObj = JsonConvert.DeserializeObject<RootObject>(secondJson);
    firstObj.MergeWith(secondObj);
    

    小提琴:https://dotnetfiddle.net/8Fiwsd

    【讨论】:

    • 非常感谢,这对我进行反序列化很有帮助。以我目前的知识,我需要很长时间才能找到这个答案,哈哈。顺便说一句,我正在尝试使用 JsonConver.PopulateObject 来组合列表。例如,Jason 可能在第一个列表中将篮球列为他的爱好,而在第二个列表中,同样的 Jason 将足球列为他的爱好。所以我希望 Jason 将他的两个爱好都列在一个列表中,但由于某种原因 PopulateObject 不起作用.. 有什么想法吗?还是应该起作用,这可能是我的一些错误?
    • @Jonas - 我已经更新了我的答案以解决您的评论。简而言之,PopulateObject 将无法像您想要的那样合并对象。您需要编写自定义逻辑来执行此合并。
    【解决方案2】:

    两者都包含List&lt;Person&gt;。像往常一样将它们反序列化为两个类,但只需获取每个类的 List 并将它们添加到同一个 List 中,因为它们包含相同的信息。

    【讨论】:

      【解决方案3】:

      您可以将您的“不同”字符串传递给不同的JObjects。然后从它们中获取不同名称的内部集合(JObject 允许这样做),然后将这些集合反序列化为具有一个通用 c# 类的集合。

      看起来像是从反序列化部分JSON区域,所以,你可以看看this link

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-01-12
        • 1970-01-01
        • 2020-08-21
        • 2019-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多