如何使用 JSON.NET 将 JSON 数组中的对象名称用作 属性 值?

How can I use the object name in a JSON array as a property value using JSON.NET?

我有以下 JSON 块(从完整的 JSON 中提取以简化问题):

 "statistics": [
  {
    "Strength": {
      "min": 16,
      "max": 20
    }
  },
  {
    "Dexterity": {
      "min": 16,
      "max": 20
    }
  }]

我想将 "statistics" 数组反序列化为 "Statistic" 对象的 C# 数组,但我可以"t find how to do it... The key of each statistic object can be anything : "Strength","Luck","Dexterity" 等等,每个键都是唯一的。

C# 数据对象应该是这样的:

public class Container
{
    public Statistic[] Statistics { get; set; }
}

public class Statistic
{
    //Contains the name of the statistic
    public string Name { get; set; }
    public int Min { get; set; }
    public int Max { get; set; }
}

也许我可以通过删除 Name 属性 并创建所有可能的 类 统计信息来使用某种多态性,但这会破坏我的代码的适应性。

非常感谢。

给定提供的 JSON,我们不能直接使用 Dictionary 结构,这是因为我们有一个对象数组,其中每个对象都有 Statistic 名称作为属性 名称(虽然它应该是一个名为 Name 的 属性 的值)

为避免处理自定义转换器,这里有一个快速(非生产就绪!)解决方案,可以为您提供一个良好的起点。 这个想法是将其反序列化为 dynamic,然后将 statistics 对象提取为 JArray 并从那里构建结果结构。

请注意,我没有检查任何内容是否为 null,因此只要输入格式正确(您需要来自 NuGet 的 Newtonsoft.Json),它就可以工作。

using System;
using System.Linq;
using Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Whosebug
{
    internal class Program
    {
        private static readonly string _inputJson =
            @"
{
    ""statistics"": [
        {
            ""Strength"": {
                ""min"": 16,
                ""max"": 20
            }
        },
        {
            ""Dexterity"": {
                ""min"": 16,
                ""max"": 20
            }
        }]
}
";

        private static void Main(string[] args)
        {
            var tempObject = JsonConvert.DeserializeObject<dynamic>(_inputJson).statistics as JArray;

            var result = new Container
            {
                Statistics = tempObject.Select(obj =>
                {
                    var token = obj.First as JProperty;
                    var stats = token.Value;
                    return new Statistic
                    {
                        Name = token.Name,
                        Min = Convert.ToInt32((stats["min"] as JValue).Value),
                        Max = Convert.ToInt32((stats["max"] as JValue).Value)
                    };
                }).ToArray()
            };

            foreach (var stat in result.Statistics) Console.WriteLine($"{stat.Name} = ({stat.Min}, {stat.Max})");
        }
    }
}

namespace Models
{
    public class Container
    {
        public Statistic[] Statistics { get; set; }
    }

    public class Statistic
    {
        //Contains the name of the statistic
        public string Name { get; set; }
        public int Min { get; set; }
        public int Max { get; set; }
    }
}

这是我得到的输出:

Strength = (16, 20)

Dexterity = (16, 20)

您可以使用简单的 JsonConverter 为您的 Statistic class 处理这个棘手的 JSON,如下所示:

class StatisticConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Statistic);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        JProperty prop = jo.Properties().First();
        Statistic stat = new Statistic
        {
            Name = prop.Name,
            Min = (int)prop.Value["min"],
            Max = (int)prop.Value["max"]
        };
        return stat;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

要使用它,请将 [JsonConverter] 属性添加到 Statistic class,它应该会按预期工作:

[JsonConverter(typeof(StatisticConverter))]
public class Statistic
{
    public string Name { get; set; }
    public int Min { get; set; }
    public int Max { get; set; }
}

这是一个工作演示:https://dotnetfiddle.net/H7wR0g

如果您不能(或不想)将属性添加到 Statistic class,您也可以通过将其传递给 DeserializeObject 方法来使用转换器,例如这个:

var container = JsonConvert.DeserializeObject<Container>(json, new StatisticConverter());

Fiddle: https://dotnetfiddle.net/UTLzBk