无法使用JsonUtility反序列化数据

时间:2019-12-30 10:45:11

标签: c# unity3d serialization

我是使用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;
}```

2 个答案:

答案 0 :(得分:3)

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}}}";

答案 1 :(得分:0)

由于您没有发送GET请求,因此您尝试访问的是 var result = lst .GroupBy(l => l.BirthDate) .Select(cl => new { BirthDate = cl.First().BirthDate, Count = cl.Count().ToString() }).ToList(); DataTable dt = Utility.ConvertToDataTable(result); chart2.DataSource = dt; chart2.Name = "BirthDate"; chart2.Series["Series1"].XValueMember = "BirthDate"; chart2.Series["Series1"].YValueMembers = "Count"; this.chart2.Titles.Remove(this.chart1.Titles.FirstOrDefault()); this.chart2.Titles.Add("Weekly Enrollment Chart"); chart2.Series["Series1"].IsValueShownAsLabel = true; ,它为NULL(因此,“ NullReferenceException:对象引用未设置为对象的实例”)。

如果您点击此链接on how to use UnityWebRequest.Get,您将发现不仅需要request.downloader.text来从URL中获取JSON字符串。

尝试以下方法:

UnityWebRequest.Get("Your_Url");

希望这会对您有所帮助。