无法使用 JsonUtility 反序列化数据 [重复]

Posted

技术标签:

【中文标题】无法使用 JsonUtility 反序列化数据 [重复]【英文标题】:Cannot deserialize data with JsonUtility [duplicate] 【发布时间】:2019-12-30 10:45:11 【问题描述】:

我是使用 Json 的新手,我无法弄清楚为什么数据没有反序列化。我尝试了很多东西,但我不知道问题是什么。 首先我需要从这个链接获取数据https://jsonplaceholder.typicode.com/users 然后我需要反序列化它。 (需要使用REST请求)

每当我想使用任何属性时,它都会告诉我它的 NULL“NullReferenceException:对象引用未设置为对象的实例”

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Net;
using System.IO;

public class Houses : MonoBehaviour

    public GameObject Prefab;

    void Update()
    
        if (Input.GetKey(KeyCode.T))
         
            onClick();
        
    


    public void onClick()
    

        UnityWebRequest request = UnityWebRequest.Get("https://jsonplaceholder.typicode.com/users");

        RootObject[] rootObjects = JsonUtility.FromJson<RootObject[]>(request.downloadHandler.text);




        //Debug.Log(request.downloadHandler.text);
        //foreach (var item in rootObjects)
        //
        //    Debug.Log(item.id);
        //



        //----------------------------------------------------------------------------------------
        //Latitude is the Y axis, longitude is the X axis

        //for (int i = 0; i < rootObjects.Length; i++)
        //
        //    float x = float.Parse(rootObjects[i].address.geo.lng);
        //    float y = float.Parse(rootObjects[i].address.geo.lat);

        //    Instantiate(Prefab, new Vector3(x, y, 0f), Quaternion.identity);
        //








    





//public class ListItems
//
//    //public RootObject[] rootObjects;

    //public List<RootObject> rootObjects;
//
[System.Serializable]
public class Geo

    public string lat  get; set; 
    public string lng  get; set; 


[System.Serializable]
public class Address

    public string street  get; set; 
    public string suite  get; set; 
    public string city  get; set; 
    public string zipcode  get; set; 
    public Geo geo  get; set; 


[System.Serializable]
public class Company

    public string name  get; set; 
    public string catchPhrase  get; set; 
    public string bs  get; set; 


[System.Serializable]
public class RootObject

    public int id; // get; set; 
    public string name  get; set; 
    public string username  get; set; 
    public string email  get; set; 
    public Address address  get; set; 
    public string phone  get; set; 
    public string website  get; set; 
    public Company company  get; set; 

如果有人可以帮助我,我将不胜感激。

编辑: 所以我做了一些改变。多亏了你们,我没有给 UnityWebRequest 时间来获取数据。 现在我得到一个不同的错误“ArgumentException:JSON 必须代表一个对象类型。”

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Net;
using System.IO;

public class Houses : MonoBehaviour

    public GameObject Prefab;
    public string jsonURL;

    void Update()
    
        if (Input.GetKeyUp(KeyCode.T))
         
            onClick();
        
    

    public void processJsonData(string _url)
    
        RootObject[] rootObjects = JsonUtility.FromJson<RootObject[]>(_url);
        Debug.Log(rootObjects[0].id);
    


    IEnumerator getData()
    
        Debug.Log("Procesing data, please wait.");


        //WWW _www = new WWW(jsonURL);

        UnityWebRequest request = UnityWebRequest.Get("https://jsonplaceholder.typicode.com/users");

        yield return request.SendWebRequest();
        if (request.error == null)
        
            processJsonData(request.downloadHandler.text);
        
        else
        
            Debug.Log("Oops something went wrong.");
        
    


    public void onClick()
    



        //----------------------------------------------------------------------------------------
        //Latitude is the Y axis, longitude is the X axis

        //for (int i = 0; i < rootObjects.Length; i++)
        //
        //    float x = float.Parse(rootObjects[i].address.geo.lng);
        //    float y = float.Parse(rootObjects[i].address.geo.lat);

        //    Instantiate(Prefab, new Vector3(x, y, 0f), Quaternion.identity);
        //


        StartCoroutine(getData());
    





//public class ListItems
//
//    //public RootObject[] rootObjects;

    //public List<RootObject> rootObjects;
//

[System.Serializable]
public class Geo

    public string lat;
    public string lng;


[System.Serializable]
public class Address

    public string street;
    public string suite;
    public string city;
    public string zipcode;
    public Geo geo;


[System.Serializable]
public class Company

    public string name;
    public string catchPhrase;
    public string bs;


[System.Serializable]
public class RootObject

    public int id;
    public string name;
    public string username;
    public string email;
    public Address address;
    public string phone;
    public string website;
    public Company company;
```

【问题讨论】:

你能试试JsonConvert.DeserializeObject&lt;RootObject[]&gt;(request.downloadHandler.text)吗?在你调试的时候,你在request.downloadHandler.text看到了什么价值? 你在哪里发送请求? 对不起,我没有提到这一点,我需要使用 JsonUtility(这是我需要做的作业)。但它仍然不允许我使用 JsonConvert。 我需要向此链接jsonplaceholder.typicode.com/users 发送请求并从中获取信息以使用它。我什至不知道我是否正确使用了 UnityWebRequest,因为我对此很陌生。 @Selvin 在使用UnityWebRequest.Get 时会自动分配它,它会创建一个新的UnityWebRequest,其中包含下载文本的标准获取请求所需的所有组件。 【参考方案1】:

Untiy 的JsonUtility 是一个相对高效但也极其有限的序列化程序。它只支持序列化fields,而你试图反序列化的对象完全由properties组成,它不支持。

(顺便说一句,Unity 的默认序列化程序不支持属性,这也是为什么它们不显示在编辑器中而字段支持的原因。)

由于它不知道如何设置属性,所以它不知道,并且该属性保持其默认值。对于引用类型(stringAddress 等),默认值为 NULL,这使得尝试访问它们会引发异常。

在你的情况下,你所要做的就是改变你想要反序列化的类,这样:

    public class Geo
    
        public string lat  get; set; 
        public string lng  get; set; 
    

变成这样:

    public class Geo
    
        public string lat;
        public string lng;
    

为你的所有课程都这样做,你应该是金子。

编辑:正如 Philip B. 在他的回答中提到的,您也没有正确使用 UnityWebRequest.Get

UnityWebRequest 不会立即解析,您必须从 Unity Coroutine 内部对它进行 yield return... 处理,或者等待它通过阻塞循环解析,如下所示:

UnityWebRequest request = UnityWebRequest.Get("https://jsonplaceholder.typicode.com/users");

request.SendWebRequest();

while (!request.isDone) 

当然,这被认为是非常糟糕的形式,因为它会冻结游戏直到下载数据。但是,under the hood Unity handles the downloads on background threads,因此您在等待时不会阻止下载本身。

您还应该查询请求以查看是否出现任何错误,以便您可以根据需要处理它们,因为您可能还会遇到下载本身的问题。

if (request.isHttpError || request.isNetworkError)

    //... handle errors here

else

    RootObject[] rootObjects = JsonUtility.FromJson<RootObject[]>(request.downloadHandler.text);

但是,我真的建议您在此处使用 Unity 的 UnityWebRequest.Get documentation 中描述的协程。如果您是 Unity Coroutines 的新手,请read up,它是 Unity 开发的宝贵工具。

编辑 2: Per this answer JsonUtility 不支持将数组序列化为***对象,因此您必须首先将数组包装在一个对象中,然后对其进行反序列化。您还必须使 json 文件中的***对象成为包含该数组的对象。

[Serializable]
public class Routes

    public RootObject[] roots;

如果您不控制文件的内容,(这个想法再次来自我链接到的那个出色的答案),您可以使用一些字符串魔术来做到这一点。

string jsonString = $@"""roots"":request.downloadHandler.text";

【讨论】:

所以你说我需要摆脱所有的 get;放; ?我试过了,但我仍然得到同样的错误。 查看我的编辑,Phillip B. 没有正确使用网络请求是正确的。 谢谢:)。我编辑了我的帖子,现在出现了另一个错误 @Klemen 这实际上是一个新问题,因为现在看来您现在成功下载的文本格式为 Unity JsonUtility 无法理解的格式。请结帐Serialize and Deserialize Json and Json Array in Unity 在那里添加了另一个编辑,祝你好运。【参考方案2】:

您正在尝试访问为 NULL 的 request.downloader.text(因此“NullReferenceException:对象引用未设置为对象的实例”),因为您没有发送 GET 请求。

如果您点击此链接 on how to use UnityWebRequest.Get,您会发现您需要的不仅仅是 UnityWebRequest.Get("Your_Url"); 从 URL 中获取您的 JSON 字符串。

尝试以下方法:

public void onClick() 
 
    using (UnityWebRequest request = UnityWebRequest.Get("https://jsonplaceholder.typicode.com/users"))
    
        request.SendWebRequest();

        RootObject[] rootObjects = JsonUtility.FromJson<RootObject[]>(request.downloadHandler.text); 
    

希望这会对你有所帮助。

【讨论】:

这甚至不会编译 我试过了,我只是删除了yield return,因为我有 void 并添加了Debug.Log(rootObjects[0].id); 以查看它是否有效,它仍然给了我同样的错误。 @Selvin 谢谢,我的错误在这里。 @Klemen,你能尝试调试一下,看看你的 request 里面有什么吗?检查您的request.downloadHandler 是否为空。 是的,它为空。因为我没有给它时间来获取数据。我制作了一个 IEnumerator 来获取数据。

以上是关于无法使用 JsonUtility 反序列化数据 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

无法在 Unity 5.4 中使用 JsonUtility 反序列化 JSON。子集合始终为空

Unity中使用JsonUtility.FromJson反序列化JSON

Unity C# JsonUtility 未序列化列表

如何反序列化 json 数组?

Unity JsonUtility 没有正确地将字符串转换为对象

枚举类型的 JSON 反序列化