【问题标题】:Json Serialization in Unity - NullReferenceException : Object reference not set to an instance of an objectUnity 中的 Json 序列化 - NullReferenceException:对象引用未设置为对象的实例
【发布时间】:2020-09-03 01:03:55
【问题描述】:

我创建了几个自定义类来读取 Unity 中的 json 文件。

Fruits.cs

[System.Serializable]
public class Fruits 
{
    public Apple[] apples;
}

Apple.cs

[System.Serializable]
public class Apple 
{
    public string appleName;
}

MyClass.cs

public class MyClass : MonoBehaviour{

private Fruits fruits;

public void classSetup(){
    StartCoroutine(JsonReader());     
    String appleName = fruits.apples[0].appleName;   -------> this is the line trigger the exception. 
    Debug.Log(appleName); 
}

Ienumerator JsonReader(){
   .........unrelated codes hidden...............
   if (Url.Contains(":/") || Url.Contains("://") || Url.Contains(":///"))
        {
            UnityWebRequest www = UnityWebRequest.Get(Url);
            yield return www.SendWebRequest();
            JsonText = www.downloadHandler.text;
        }

        fruits = JsonUtility.FromJson<Fruits>(JsonText);

}
}

JsonReader(我创建的 IEnumerator)工作正常,因为 Debug.Log 打印出我期望的 appleName,但“String appleName .....”行触发异常(NullReferenceException:对象引用未设置为对象。)

我阅读了有关如何修复空异常的帖子,但无法找到有关如何为自定义序列化类执行此操作的帮助。简单地做 fruits = new Fruits() 是行不通的。我怀疑那是因为我没有实例化这些字段。但是,如果我在 Fruits 类中有很多字段怎么办?如果我不能只做“fruits.apples = new Apple[5]”,因为长度取决于 json 输入并且可能不是 5?

任何帮助将不胜感激。

【问题讨论】:

  • 除非JsonReader() 返回的枚举器被迭代(可能在StartCoroutine() 内?),否则fruits = JsonUtility.FromJson&lt;Fruits&gt;(JsonText); 行永远不会到达,因此fruits 永远不会被初始化。
  • fruits = ... 行放一个断点,看看调试器是否停在那里(可能不会)。否则,请尝试创建minimal reproducible example 并将其包含在问题中。

标签: c# json unity3d


【解决方案1】:

我不完全确定那个。但我认为问题在于,Unity 过早地到达字符串 apple 因为您启动了一个协程,并且在您创建 json 对象时,Unity 正在继续并尝试获取一个值,但这还不存在。所以你可以尝试自定义事件。

//Create a delegate and and event to fire at a certain point of time
public delegate void FruitsLoadedEvent FruitsLoadedEvent();
public static event FruitsLoadedEvent OnFruitsLoaded;

public void classSetup(){
    //Subscribe to the event
    OnFruitsLoaded += CreateApple;
    StartCoroutine(JsonReader());     
}

Ienumerator JsonReader(){
    .........unrelated codes hidden...............
    if (Url.Contains(":/") || Url.Contains("://") || Url.Contains(":///"))
    {
        UnityWebRequest www = UnityWebRequest.Get(Url);
        yield return www.SendWebRequest();
        JsonText = www.downloadHandler.text;
    }

    fruits = JsonUtility.FromJson<Fruits>(JsonText);
    //Invoke the event after checking, if anyone is subscribed
    OnFruitsLoaded?.Invoke();
}

private void CreateApple() {
    String appleName = fruits.apples[0].appleName;
}

希望对你有所帮助!

【讨论】:

    【解决方案2】:

    启动协程不会延迟启动它的方法本身。如果这样做是没有意义的,因为您将失去将其设为协程的全部原因。

    您想要做的是将您的代码移动到收到结果之后执行的代码,例如

    public class MyClass : MonoBehaviour
    {  
        public void classSetup()
        {
            StartCoroutine(JsonReader());     
        }
    
        IEnumerator JsonReader()
        {
           // .........unrelated codes hidden...............
           if (Url.Contains(":/") || Url.Contains("://") || Url.Contains(":///"))
           {
                UnityWebRequest www = UnityWebRequest.Get(Url);
                yield return www.SendWebRequest();
                JsonText = www.downloadHandler.text;
            }
    
            var fruits = JsonUtility.FromJson<Fruits>(JsonText);
    
            String appleName = fruits.apples[0].appleName;   -------> this is the line trigger the exception. 
            Debug.Log(appleName); 
       }
    }
    

    或者使用回调

    public class MyClass : MonoBehaviour
    {
        public void classSetup()
        {
            StartCoroutine(JsonReader(HandleResult));     
    
            // or the same as lambda expression
            //StartCoroutine(JsonReader(fruits => 
            //{
            //    String appleName = fruits.apples[0].appleName;   -------> this is the line trigger the exception. 
            //    Debug.Log(appleName); 
            //}));
        }
    
        IEnumerator JsonReader(Action<Fruits> onResult)
        {
           // .........unrelated codes hidden...............
           if (Url.Contains(":/") || Url.Contains("://") || Url.Contains(":///"))
           {
                UnityWebRequest www = UnityWebRequest.Get(Url);
                yield return www.SendWebRequest();
                JsonText = www.downloadHandler.text;
            }
    
            var fruits = JsonUtility.FromJson<Fruits>(JsonText);
    
            onResult?.Invoke(fruits);
       }
    
       private void HandleResult(Fruits fruits)
       {
           String appleName = fruits.apples[0].appleName;   -------> this is the line trigger the exception. 
           Debug.Log(appleName); 
       }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-07-21
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 2022-08-13
      • 2016-10-22
      • 2013-04-19
      • 2016-06-05
      • 1970-01-01
      相关资源
      最近更新 更多