【问题标题】:Creating a C# class from convoluted JSON object where dynamic variable would be class name [duplicate]从复杂的 JSON 对象创建一个 C# 类,其中动态变量是类名 [重复]
【发布时间】:2020-10-17 05:12:56
【问题描述】:

我正在尝试使用 wikimedia API 从 wikipedia 文章中查询最重要的信息。在我的代码中,我有以下行:

WikiArticleModel article = await response.Content.ReadAsAsync<WikiArticleModel>().ConfigureAwait(false);

这是我的 JSON 对象在对木星行星上的文章进行测试时的外观示例:

{
    "batchcomplete": "",
    "query": {
        "normalized": [
            {
                "from": "jupiter",
                "to": "Jupiter"
            }
        ],
        "pages": {
            "38930": {
                "pageid": 38930,
                "ns": 0,
                "title": "Jupiter",
                "extract": ">>> Her comes the first section of the article, which I deleted to make 
                  this shorter <<<",
                "description": "Fifth planet from the Sun and largest planet in the Solar System",
                "descriptionsource": "local",
                "original": {
                    "source": "https://upload.wikimedia.org/wikipedia/commons/2/2b/Jupiter_and_its_shrunken_Great_Red_Spot.jpg",
                    "width": 940,
                    "height": 940
                }
            }
        }
    }
}

现在的问题是,我的WikiArticleModel 班级应该是什么样子?也使用内置的 VS Studio “将 JSON 粘贴为类”,我得到以下结果:

public class WikiArticleModel
{
    public string batchcomplete { get; set; }
    public Query query { get; set; }
}

public class Query
{
    public Normalized[] normalized { get; set; }
    public Pages pages { get; set; }
}

public class Pages
{
    public _38930 _38930 { get; set; }
}

public class _38930
{
    public int pageid { get; set; }
    public int ns { get; set; }
    public string title { get; set; }
    public string extract { get; set; }
    public string description { get; set; }
    public string descriptionsource { get; set; }
    public Original original { get; set; }
}

public class Original
{
    public string source { get; set; }
    public int width { get; set; }
    public int height { get; set; }
}

public class Normalized
{
    public string from { get; set; }
    public string to { get; set; }
}

除了 _38930 类之外,这是可以的,我期望的是,它只是 pageid 并且会随着每个查询而改变。 反序列化此对象的正确方法是什么?或者在这种情况下,仅获取 object 作为响应并手动填充模型类是更好的方法吗?

此外,我实际上只需要来自JSON 对象的某些参数(例如标题、提取、描述等) - 有没有办法将这些参数直接放入仅包含我需要的属性的模型类中?

【问题讨论】:

    标签: c# json api serialization


    【解决方案1】:

    这是原生的方式,Pages实际上是一个Dictionary

    public class WikiArticleModel
    {
        public string batchcomplete { get; set; }
        public Query query { get; set; }
    }
    
    public class Query
    {
        public List<Normalized> normalized { get; set; }
    
        public Pages pages { get; set; }
    }
    
    [JsonDictionary]
    public class Pages : Dictionary<int, Page> { }
    
    public class Page
    {
        public int pageid { get; set; }
        public int ns { get; set; }
        public string title { get; set; }
        public string extract { get; set; }
        public string description { get; set; }
        public string descriptionsource { get; set; }
        public Original original { get; set; }
    }
    
    public class Original
    {
        public string source { get; set; }
        public int width { get; set; }
        public int height { get; set; }
    }
    
    public class Normalized
    {
        public string from { get; set; }
        public string to { get; set; }
    }
    

    【讨论】:

    • 当然,这与建议的副本中的答案相同。
    • @HereticMonkey 本质上是的,但是对于像我这样的新手来说,我在使用 JSON 时,这个答案可以帮助我更轻松地解决和理解我的具体问题。虽然一般解决方案是相同的,但我会保持原样。
    • @RolandDeschain Stack Overflow 的存在是为了创建一个问题和答案的知识库,而不是让每个可能提出问题的字符排列都有。目标是在一个地方收集同一问题的优质、高质量答案。重复的问题很好——它们可以作为向人们指出正确答案的路标——但它们应该被关闭。见the help center article on duplicates
    • 虽然答案几乎相同,但问题却不同。在此示例中,您正在查看字典并不是很明显(因为嵌套和单个项目),尤其是对于没有经验的程序员。
    【解决方案2】:

    我建议使用 Newtonsoft.Json.Linq 中的 JObject.Parse 并根据该页面的键名对其进行解析。像这样的,

    public class Page
    {
        public int pageid { get; set; }
        public int ns { get; set; }
        public string title { get; set; }
        public string extract { get; set; }
        public string description { get; set; }
        public string descriptionsource { get; set; }
        public Original original { get; set; }
    }
    
    public class Original
    {
        public string source { get; set; }
        public int width { get; set; }
        public int height { get; set; }
    }
    
    public class Normalized
    {
        public string from { get; set; }
        public string to { get; set; }
    }
    
    // you can deserialize like this,
    
    var jobj = JObject.Parse(json);
    var props = ((JObject)jobj["query"]["pages"]).Properties();
    Page page = JsonConvert.DeserializeObject<Page>(jobj["query"]["pages"][props.First().Name].ToString());
    

    您可以在页面的每个属性上使用 foreach 循环并遍历这些属性(而不是使用 props.First()

    【讨论】:

    • 所以 httpclient 应该给我一个像 vararticle = await response.Content.ReadAsAsync&lt;object&gt;().ConfigureAwait(false); 这样的对象,然后我按照你的描述反序列化它?
    • 应该可以的
    猜你喜欢
    • 2016-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多