【问题标题】:How to deserialize a list of values to C# objects如何将值列表反序列化为 C# 对象
【发布时间】:2020-02-12 19:12:39
【问题描述】:

我的应用程序收到一个 JSON 对象:

{
  "names": [
    "name_1",
    "name_2"
  ]
}

我想将其反序列化为Person对象列表,定义为:

class Person
{
    public string Name { set; get; }
}

目前,我将 JSON 对象反序列化为字符串列表,然后手动创建 Person 列表,如下所示:

var names = JsonConvert.DeserializeObject<List<string>>(json);
var people = new List<Person>();
foreach(var name in names)
    people.Add(new Person(){ Name = name });

相反,我对以下内容感兴趣:

var people = JsonConvert.DeserializeObject<List<Person>>(json);

我将Person 解串器实现为:

public class PersonJsonConverter : JsonConverter
{
    private readonly Dictionary<string, string> _propertyMappings;

    public PersonJsonConverter()
    {
        _propertyMappings = new Dictionary<string, string>
        {
            {"name", nameof(Person.Name)}
        };
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.GetTypeInfo().IsClass;
    }

    public override object ReadJson(
        JsonReader reader,
        Type objectType,
        object existingValue,
        JsonSerializer serializer)
    {
        object instance = Activator.CreateInstance(objectType);
        var props = objectType.GetTypeInfo().DeclaredProperties.ToList();

        JObject obj = JObject.Load(reader);
        foreach (JProperty jsonProperty in obj.Properties())
        {
            if (!_propertyMappings.TryGetValue(jsonProperty.Name, out var name))
                name = jsonProperty.Name;

            PropertyInfo prop = props.FirstOrDefault(
                pi => pi.CanWrite && pi.Name == name);

            prop?.SetValue(
                instance,
                jsonProperty.Value.ToObject(prop.PropertyType, serializer));
        }

        return instance;
    }
}

这个反序列化器可以反序列化对象,例如:

{
  "names": [
    "name": "name_1",
    "name": "name_2"
  ]
}

但不是

{
  "names": [
    "name_1",
    "name_2"
  ]
}

请注意,我的应用程序可以接收这两种类型的 JSON 对象,因此最好为这两种类型使用一个通用的反序列化器。

【问题讨论】:

    标签: c# json .net-core


    【解决方案1】:

    请尝试以下:

    class Person
    {
        public string Name { set; get; }
    }
    
    public class PersonJsonConverter : JsonConverter
    {
        // private readonly Dictionary<string, string> _propertyMappings;
    
        public PersonJsonConverter()
        {
            /*_propertyMappings = new Dictionary<string, string>
            {
                {"name", nameof(Person.Name)}
            };*/
        }
    
        public override bool CanConvert(System.Type objectType)
        {
            return objectType.GetTypeInfo().IsClass;
        }
    
        public override object ReadJson(JsonReader reader, System.Type objectType, object existingValue, JsonSerializer serializer)
        {
            object instance = Activator.CreateInstance(objectType);
            // List<T> implements the non-generic IList interface
            IList list = (IList)instance;
            var typeInfo = objectType.GetTypeInfo();
            var props = typeInfo.DeclaredProperties.ToList();
            PropertyInfo prop = props.FirstOrDefault(pi => pi.PropertyType == typeof(Person));
    
            JObject obj = JObject.Load(reader);
            var namesArray = obj["names"]; // you can use this instead of for loop on obj.Properties.
            /*foreach (JProperty jsonProperty in obj.Properties())
            {
                if (jsonProperty.Name == "names")
                {
                    var namesArray = JArray.Parse(jsonProperty.Value.ToString());
                    */
                    if (namesArray.Type == JTokenType.Array && prop != null)
                    {
                        foreach (var ja in namesArray)
                        {
                            object personInstance = Activator.CreateInstance(prop.PropertyType);
                            PropertyInfo personNamePropInfo = prop.PropertyType.GetProperty(nameof(Person.Name));
                            personNamePropInfo.SetValue(personInstance,
                                Convert.ChangeType(ja, personNamePropInfo.PropertyType), null);
                            list.Add(personInstance); // Whatever you need to add
                        }
                    }
    
              /*      break;
                }
            }*/
    
            return instance;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    并像下面这样使用它:

    var samplejson = @"{
      ""names"": [
        ""name_1"",
        ""name_2""
      ]
    }";
    var obj = JsonConvert.DeserializeObject<List<Person>>(samplejson,   new JsonConverter[] { new PersonJsonConverter() });
    

    另一个 json 似乎不是有效的 json。

    【讨论】:

    • 我期待一个对我拥有的反序列化器进行更少更改的答案;无论如何,谢谢。
    【解决方案2】:

    您必须将names 反序列化为JArray,然后将foreachnew Person('name') 的每个条目反序列化。您收到的 JSON 与您想要的架构不匹配。你必须手动转换它。

    【讨论】:

    • 这有点像我已经在做的事情,但我对更改反序列化器以捕获/反序列化两种方案很感兴趣。
    猜你喜欢
    • 2022-01-19
    • 2017-06-10
    • 2016-05-30
    • 2018-10-11
    • 2022-12-13
    • 2020-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多