C#的JSON列表转换器

4

我完全是一个C#初学者。我正在尝试在C#中转换JSON数据。我在列表方面遇到了一些困难。只要我能转换基本方法,就会在那个带有列表的方法中出现错误。你介意给我一些建议来解决我的问题吗?

原始JSON数据

[{"data": {"Temperature": {"data": {"2018-07-04 13:05:00": 20.9224991798401}, "meta": {"units": "Celsius", "name": "Temperature", "theme": "Weather"}}}, "latest": "2018-07-04 13:05:00", "sensor_height": -999, "type": "Weather", "base_height": -999, "geom": {"coordinates": [-1.62469, 54.98274], "type": "Point"}, "active": "True", "name": "sportshall_oat", "source": {"document": null, "fancy_name": "BMS", "db_name": "Bms", "third_party": false, "web_display_name": "BMS"}}]

主类

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            var client = new WebClient();

            var text = client.DownloadString("http://uoweb1.ncl.ac.uk/api/v1/sensor/live.json?sensor_name=sportshall_oat&api_key=4dopcdjiu3wtzfl32hn94hbf5ubm3q89jbh18iaxaqdzc10nlgbebqqvxqyt3ymydi59fjnyrmuqtgtdxb1sm5msac");

            Rootobject ro = JsonConvert.DeserializeObject<Rootobject>(text);
            Console.WriteLine("current time = " + ro.Property1);

            Class1 c1 = JsonConvert.DeserializeObject<Class1>(text);

            Data data = JsonConvert.DeserializeObject<Data>(text);

            Temperature temperature = JsonConvert.DeserializeObject<Temperature>(text);
            Console.WriteLine("data = " + temperature.data);

            Data1 d1 = JsonConvert.DeserializeObject<Data1>(text);

            Meta meta = JsonConvert.DeserializeObject<Meta>(text);

            Geom geom = JsonConvert.DeserializeObject<Geom>(text);

            Source source = JsonConvert.DeserializeObject<Source>(text);

         }
    }
}

JSON数据(由Visual Studio生成)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{

    public class Rootobject
    {
        public Class1[] Property1 { get; set; }
    }

    public class Class1
    {
        public Data data { get; set; }
        public string latest { get; set; }
        public int sensor_height { get; set; }
        public string type { get; set; }
        public int base_height { get; set; }
        public Geom geom { get; set; }
        public string active { get; set; }
        public string name { get; set; }
        public Source source { get; set; }
    }

    public class Data
    {
        public Temperature Temperature { get; set; }
    }

    public class Temperature
    {
        public Data1 data { get; set; }
        public Meta meta { get; set; }
    }

    public class Data1
    {
        public float _20180704130500 { get; set; }
    }

    public class Meta
    {
        public string units { get; set; }
        public string name { get; set; }
        public string theme { get; set; }
    }

    public class Geom
    {
        public float[] coordinates { get; set; }
        public string type { get; set; }
    }

    public class Source
    {
        public object document { get; set; }
        public string fancy_name { get; set; }
        public string db_name { get; set; }
        public bool third_party { get; set; }
        public string web_display_name { get; set; }
    }

}

当我试图运行程序时,控制台会崩溃。调试后,我可以确定问题所在,但不知道如何修复它。这是错误消息:
Newtonsoft.Json.JsonSerializationException:'无法将当前JSON数组(例如[1,2,3])反序列化为类型“ConsoleApp2.Rootobject”,因为该类型需要JSON对象(例如{"name":"value"})才能正确反序列化。
要解决此错误,请将JSON更改为JSON对象(例如{"name":"value"}),或将反序列化类型更改为数组或实现集合接口的类型(例如ICollection、IList),如List,可以从JSON数组中反序列化。也可以向该类型添加JsonArrayAttribute以强制将其从JSON数组反序列化。
预先感谢大家的帮助。

2
方括号 [] 表示这是一个 JSON 数组。在这种情况下,反序列化为 List<RootObject> 是最常见的解决方案,因此 var ro = JsonConvert.DeserializeObject<List<Rootobject>>(text); - Equalsk
@Equalsk 更像是 List<Class1>,但基本上是正确的 :) - DavidG
反序列化JSON后,您将不再需要进行任何进一步的反序列化,您只需能够从初始类中访问所有内容。 - Frauke
2
@DavidG 只是在确认其他人都还清醒,诚实地说... - Equalsk
1
干得好!这是你的第一个问题,你提供了我们需要帮助你的所有相关信息。你会惊讶地发现,在第一次尝试时,有多少人无法做到这一点! - Jamiec
3个回答

3

您的RootObject是错误的,Class1的命名不好,但它基本上是正确的结构来反序列化数据 - 然而数据是一个Class1数组。您可以使用List<Class1>或者Class1[](数组) - 两者都应该可以工作:

var client = new WebClient();
var text = client.DownloadString("http://uoweb1.ncl.ac.uk/api/v1/sensor/live.json?sensor_name=sportshall_oat&api_key=4dopcdjiu3wtzfl32hn94hbf5ubm3q89jbh18iaxaqdzc10nlgbebqqvxqyt3ymydi59fjnyrmuqtgtdxb1sm5msac");
var result = JsonConvert.DeserializeObject<List<Class1>>(text);

你不需要单独反序列化所有的子部分,例如可以这样做:

var name = result[0].name;

(注:您的列表只有一个项目,因此需要请求索引为0的列表项,然后是您想要的任何属性)。
我不会再重复关于您的Temperature类的警告,但请参见@DavidG的答案

谢谢您的回复。我仍然不确定最后一行“var name = result.name;”是什么意思。您介意解释一下,我应该写什么来显示控制台中的数据,而不是“name”吗?我试图调用Temperature方法来显示温度,但是我收到了错误消息,“Temperature”不是Class1的一部分。 - Monika
@Monika 这只是为了演示一旦反序列化,您可以读取任何属性。要获取Temperature,它在Data类中,因此使用result.data.Temperature。要写入控制台,您可以使用非常直观命名的Console.WriteLine(result.data.Temperature);方法。希望这有所帮助。 - Jamiec
好的,那就是我试图运行的内容。我写了"var temp = result.data.Temperature;",然后再写了"Console.WriteLine(temp);" 但是出现了错误提示:"List<Class1>没有定义'data',也找不到接受类型为'List<Class1>'第一个参数的扩展方法'data'(是否缺少using指令或程序集引用?)"。 - Monika
哦,抱歉我的错。您的列表只有1个项目。var temp = result[0].data.Temperature; @Monika - Jamiec
好的,那很有道理。所以我期望看到输出的是当前日期和温度,但实际上唯一的输出是“ConsoleApp2.Temperature”。这是否意味着我的使用JSON数据的类写错了? - Monika
非常抱歉现在问了这么多问题。我花了一整天的时间来解决我的问题,现在我真的想了解它是如何工作的,而不仅仅是得到正确的答案。 - Monika

3

你的代码有几个问题。

  1. Since the JSON is surrounded by [...], it means it's an array or items so you need to use a List (or similar) structure. In your case, you can drop the Rootobject class completely and deserialise directly to a List<Class1>. For example:

    var result = JsonConvert.DeserializeObject<List<Class1>>(json);
    
  2. The Data1 class is using a date as the property name. I would suggest dropping that class completely and modify thre Temperature class to use a Dictonary<DateTime, float>:

    public class Temperature
    {
        public Dictionary<DateTime, float> data { get; set; }
        public Meta meta { get; set; }
    }
    

    And now you can cope with any DateTime being passed in, you would use it like this:

    var data = obj[0].data.Temperature.data;
    Console.WriteLine($"The temperature on {data.Key} was {data.Value}");
    

1
Temperature类做得很好! - Jamiec
谢谢您的建议,我按照您的建议修改了我的类。 - Monika
@Monika 没问题。不要忘记根据您的需要投票和接受答案。哦,还有很高兴在纽卡斯尔遇到另一个人! - DavidG
很遗憾,由于我的声望低于15,我无法投票。很高兴见到你! - Monika
@Monika,您可以选择选中最有帮助的答案旁边的勾号(我建议这个是正确的!)。这不是投票,而是标记接受(您认为)的答案。 - Jamiec
显示剩余2条评论

-2

然后你需要一个模型。根据你的JSON,它将会得到类似于这样的结果。

public class RootObject
{
    public Data data { get; set; }
    public DateTime latest { get; set; }
    public int sensor_height { get; set; }
    public string type { get; set; }
    public int base_height { get; set; }
    public Geom geom { get; set; }
    public string active { get; set; }
    public string name { get; set; }
    public Source source { get; set; }
}

public class Data
{
    public Temperature Temperature { get; set; }
    public Meta meta { get; set; }
}

public class Geom
{
    public float[] coordinates { get; set; }
    public string type { get; set; }
}

public class Source
{
    Public string document { get; set; }
    Public string fancy_name { get; set; }
    Public string db_name { get; set; }
    Public string third_party { get; set; }
    Public string web_display_name { get; set; }
}

public class Temperature 
{
    public string data { get; set; }
}

public class Meta
{
    Public string units { get; set; }
    Public string name { get; set; }
    Public string theme { get; set; }
}

创建模型后,您只需使用它即可。
var result = JsonConvert.DeserializeObject<RootObject>(your_json_string);

然后你可以像这样访问对象:

result.data..
result.latest...

等等。


这个方案不可行,原因与OP实际问题相同。 - DavidG
你的代码仍然存在与原始代码相同的问题。请查看前两个答案。 - Jamiec

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接