C# 反序列化 JSON 没有自定义 class 到字典或数据表

C# deserialize JSON without custom class into Dictionary or DataTable

从 API 我得到一个 json 这样的:

具有大约 31 个属性的玩家的 66 个结果包含单个值或值数组。

{"api":
{"results":66,
    "players":
        [{
            "player_id":10,
            "player_name":"Gustavo Ferrareis",
            ... (some 31 stats)
            "shots":{
                    "total":13,
                    "on":2
                },
            ...
          },
            "player_id":21,
            ...
       }]
     }

而且我想知道是否有办法将玩家集合反序列化为字典或更好的数据表 具有所有 31 个属性而无需自定义玩家 class 或单独访问每个属性?

到目前为止,我尝试通过以下方式访问玩家列表:

        var data = JObject.Parse(json);
        foreach (var field in data)
        {
            var data2 = JObject.Parse(field.Value.ToString());
            foreach (var field2 in data2)
            {
                if (field2.Key.ToString() == "players")
                {
                    dynamic array2 = JsonConvert.DeserializeObject(field2.Value.ToString());

                    foreach (var field3 in array2)
                        Console.WriteLine("Player_id: " + field3.player_id.ToString() + " - Player_name: " + field3.player_name.ToString());
                }
            }
        }

哪个returns

Player_id: 10 - Player_name: Gustavo Ferrareis
Player_id: 22 - Player_name: Getúlio
Player_id: 22 - Player_name: Getúlio

我想是这样的:

Dictionary<string, object> dict = new Dictionary<string, object>();

foreach (var player in array2)
    dict.Add(player.Key(), player.Value());

答案不可能是我必须制作一个自定义播放器 class 然后使用它?

欢迎任何建议。 谢谢。

您可以像这样解析成 IEnumerable<string>

IEnumerable<string> = JObject.Parse(json)["players"]
    .Children()
    .Select(jo => $"Player_id: {jo["player_id"]} - Player_name: {jo["player_name"]});

类似的方法适用于 Dictionary,使用 ToDictionary 而不是 Select,但这取决于您对键和值的看法。

这是将玩家 ID 和玩家名称设为 ListDictionary

的单行代码
//To List
var resultToList = JObject.Parse(jsonstring)["api"]["players"]
                   .Select(p => (p["player_id"].ToString(), p["player_name"].ToString()))
                   .ToList();

//To Dictionary
var resultToDict = JObject.Parse(jsonstring)["api"]["players"]
                   .Select(p => (p["player_id"].ToString(), p["player_name"].ToString()))
                   .ToDictionary(x=>x.Item1, y=>y.Item2);

您可以使用 Newtonsoft.Json.Linq 并得到所需的结果,如下所示:

var jObject = JObject.Parse(jsonFromAPI)["api"];
var formattedPlayers = jObject["Players"].Children()
                .Select(p => $"Player_id: {p["player_id"]} - Player_name: {p["player_name"]}");

或者如果你想要字典,那么使用下面的:

var playersDictionary = jObject["Players"].Children().Select(p => new {player_id = p["player_id"], player_name = p["player_name"]}).ToDictionary(x => x.player_id, v => v.player_name);

如果你想显示玩家的所有属性,那么你需要运行循环如下:

var allPlayerDetails = new List<Dictionary<string, object>>();
foreach (JObject player in jObject["Players"].Children())
{
    var playerDictionary = player.Properties()
        .ToDictionary<JProperty, string, object>(property => property.Name, property => property.Value);

    allPlayerDetails.Add(playerDictionary);
}

for (var index = 0; index < allPlayerDetails.Count; index++)
{
    var playerDictionary = allPlayerDetails[index];
    Console.WriteLine(Environment.NewLine);
    Console.WriteLine(string.Format("Printing Player# {0}", index));
    foreach (var d in playerDictionary)
    {
        Console.WriteLine(d.Key + " - " + d.Value);
    }
}

如果你想从玩家列表中转换为数据表,那么你可以执行如下操作:

DataTable dt = new DataTable();

foreach (var column in allPlayerDetails.SelectMany(p => p.Keys).Select(k => k.Trim()).Distinct())
{
    dt.Columns.Add(new DataColumn(column));
}

foreach (var details in allPlayerDetails)
{
    var dr = dt.NewRow();
    foreach (DataColumn dc in dt.Columns)
    {
        dr[dc.ColumnName] = details.ContainsKey(dc.ColumnName) ? details[dc.ColumnName] : null;
    }
    dt.Rows.Add(dr);
}

可以找到 Fiddler here