【问题标题】:Cannot deserialize data with JsonUtility [duplicate]无法使用 JsonUtility 反序列化数据 [重复]
【发布时间】: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,其中包含下载文本的标准获取请求所需的所有组件。

标签: c# unity3d serialization


【解决方案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 来获取数据。
猜你喜欢
  • 1970-01-01
  • 2019-10-12
  • 1970-01-01
  • 1970-01-01
  • 2013-04-04
  • 2018-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多