需要帮助在没有外部库的情况下在 C# 中使用泛型和属性解析 JSON

问题描述 投票:0回答:1

我正在使用泛型和自定义属性在 C# 中开发 JSON 解析器,但在将 JSON 数据正确解析到模型类中时遇到了问题。我想在不使用任何外部库的情况下实现这一目标,只需使用 .NET 的内置功能。

这是我为 JSON 创建的模型:

using System;
using System.Collections.Generic;

namespace Test3.Model
{
    public class Walks
    {
        [JsonProperty("id")]
        public int Id { get; set; }

        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("distance")]
        public double Distance { get; set; }

        [JsonProperty("duration")]
        public string Duration { get; set; }

        [JsonProperty("difficulty")]
        public string Difficulty { get; set; }

        [JsonProperty("description")]
        public string Description { get; set; }
    }
}

我还创建了一个 JsonPropertyAttribute 来帮助映射:

using System;

namespace Test3
{    
    [AttributeUsage(AttributeTargets.Property)]
    public class JsonPropertyAttribute : Attribute
    {
        public string Key { get; }
        public JsonPropertyAttribute(string key)
        {
            Key = key;
        }
    }
}

这是我的通用 JSON 解析器:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Test3
{
    public class GenericJsonParser
    {
        public static List<T> ParseJson<T>(string json) where T : new()
        {
            // Logic for parsing JSON...
        }

        private static T ParseSingleObject<T>(string json) where T : new()
        {
            // Logic for parsing a single JSON object...
        }

        private static void SetPropertyValue<T>(T obj, string key, string value)
        {
            // Logic to set property value using reflection...
        }
    }
}

我尝试解析的 JSON 如下所示:

{
  "walks": [
    {
      "id": 1,
      "name": "River Walk",
      "distance": 5.5,
      "duration": "2 hours",
      "difficulty": "Easy",
      "description": "A scenic walk along the river with beautiful views."     
    },
    {
      "id": 2,
      "name": "Mountain Trail",
      "distance": 10.2,
      "duration": "4 hours",
      "difficulty": "Moderate",
      "description": "A challenging trail through the mountains."
    },
    {
      "id": 3,
      "name": "Forest Loop",
      "distance": 3.8,
      "duration": "1 hour",
      "difficulty": "Easy",
      "description": "A peaceful walk through the forest."
    }
  ]
}

我面临的问题:
当我尝试解析 JSON 时,我只能得到一个空的 Walk 列表。
我不确定我的解析逻辑是否使用 JsonPropertyAttribute 将属性与 JSON 键正确映射。

string json = File.ReadAllText("path_to_your_json_file");
List<Walks> walksList = GenericJsonParser.ParseJson<Walks>(json);

我不确定我的解析逻辑是否使用 JsonPropertyAttribute 将属性与 JSON 键正确映射。任何有关为什么我可能会得到空列表的帮助将不胜感激!

此结构应为其他人提供足够的背景,以了解您的情况并提供相关帮助。确保包含 JSON 文件的实际路径,并在运行解析器之前验证其格式是否正确。

c# json generics reflection attributes
1个回答
0
投票

正如

@Jon Skeet
提到的,主要问题可能是(我们不能确定,因为你没有提供你尝试过的解析代码),你试图解析
Walks
,就好像它是json 的根对象。但是,您有一个包含数组 (
Walks
) 的对象(根)。

您可以通过在现有的包装类周围添加一个包装类来解决此问题,这样您就不需要任何自定义 json 解析器,并且只需使用 .

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

public class Program
{
    public class WalksWrapper
    {
        [JsonPropertyName("walks")]
        public List<Walk> Walks { get; set; }
    }

    public class Walk
    {
        [JsonPropertyName("id")]
        public int Id { get; set; }

        [JsonPropertyName("name")]
        public string Name { get; set; }

        [JsonPropertyName("distance")]
        public double Distance { get; set; }

        [JsonPropertyName("duration")]
        public string Duration { get; set; }

        [JsonPropertyName("difficulty")]
        public string Difficulty { get; set; }

        [JsonPropertyName("description")]
        public string Description { get; set; }
    }

    public static void Main()
    {
        var jsonString = """
{
  "walks": [
    {
      "id": 1,
      "name": "River Walk",
      "distance": 5.5,
      "duration": "2 hours",
      "difficulty": "Easy",
      "description": "A scenic walk along the river with beautiful views."     
    },
    {
      "id": 2,
      "name": "Mountain Trail",
      "distance": 10.2,
      "duration": "4 hours",
      "difficulty": "Moderate",
      "description": "A challenging trail through the mountains."
    },
    {
      "id": 3,
      "name": "Forest Loop",
      "distance": 3.8,
      "duration": "1 hour",
      "difficulty": "Easy",
      "description": "A peaceful walk through the forest."
    }
  ]
}
""";

        var walksWrapper = JsonSerializer.Deserialize<WalksWrapper>(jsonString);

        // Serialize it back to JSON with the indented option for pretty printing
        var prettyJson = JsonSerializer.Serialize(walksWrapper, new JsonSerializerOptions
        {
            WriteIndented = true
        });

        Console.WriteLine(prettyJson);
    }
}

https://dotnetfiddle.net/EMhBmc

© www.soinside.com 2019 - 2024. All rights reserved.