仅在Unity 3D播放器中未调试时出现NullReference错误

sam*_*uke 0 json nullreferenceexception unity-game-engine oauth-2.0

我在Unity 3D应用程序中工作,我有2个方法通过使用Oauth连接到服务:一个检索令牌,另一个根据令牌从服务检索JSON输出.一旦JSON准备就绪,我就改变了TextMesh上的文本.一切都在TextMesh脚本的start方法中运行.像这样的东西:

void Start()
{
    string authToken = getAuthToken();
    CustomerGroups data = getCustGroups(authToken);

    TextMesh curText = (TextMesh)gameObject.GetComponent(typeof(TextMesh));
    curText.text = data.value[0].Field1+ "-" + data.value[0].Field2;
}
Run Code Online (Sandbox Code Playgroud)

奇怪的是,当我在Visual Studio中使用"附加到Unity"并在Unity播放器中运行GameObject时,这非常有用,但是当我在没有调试的情况下运行它时(比如运行几个步骤)我总是得到:

NullReferenceException: Object reference not set to an instance of an object
HelloWorldInteractive.getAuthToken () (at Assets/HelloWorldInteractive.cs:106)
HelloWorldInteractive.Start () (at Assets/HelloWorldInteractive.cs:15)
Run Code Online (Sandbox Code Playgroud)

实际的方法是:

public string getAuthToken()
{
    string token = string.Empty;
    Dictionary<string, string> content = new Dictionary<string, string>();
    TokenClassName json = null;

    content.Add("tenant_id", "https//...");
    content.Add("grant_type", "client_credentials");
    content.Add("client_id", "xxxx");
    content.Add("client_secret", "xxxx");
    content.Add("resource", "https://...");

    UnityWebRequest www = UnityWebRequest.Post("https://login...", content);

    //Send request
    www.SendWebRequest();

    if (!www.isNetworkError)
    {
        string resultContent = www.downloadHandler.text;
        json = JsonUtility.FromJson<TokenClassName>(resultContent);

        //Return result
        token = json.access_token;
    }

    return token;
}
Run Code Online (Sandbox Code Playgroud)

而且,如果我不调试它,它会失败,但是当我在运行它时进行调试时,它运行良好.我假设它可能与在Start方法中执行它们有关...也许我需要在其他地方执行它?我只需要准备好JSON数据,这样我就可以在开始时更改TextMesh的值.

der*_*ugo 6

你的问题被称为"竞争条件".

当你进行调试时,你"足够慢",所以你UnityWebRequest很可能会得到一个结果,直到你找到需要它的部分代码.

虽然没有调试:你没有等到webrequest完成.

所以当方法到达该行时www.downloadHandler.text;仍然具有该值null

json = JsonUtility.FromJson<TokenClassName>(resultContent);
Run Code Online (Sandbox Code Playgroud)

我不知道exctaly JsonUtility.FromJson对于null输入值有什么作用,但我猜测错误已经在那里抛出或者它可能会返回null所以下一行

token = json.access_token;
Run Code Online (Sandbox Code Playgroud)

尝试json使用该值访问null是抛出异常.


您必须使用Coroutine,yield直到获得结果(请参阅UnityWebRequest.Post).

我会使用像这样的回调方法

private IEnumerator getAuthToken(Action<string> onSuccess)
{
    string token = string.Empty;
    Dictionary<string, string> content = new Dictionary<string, string>();
    TokenClassName json = null;

    content.Add("tenant_id", "https//...");
    content.Add("grant_type", "client_credentials");
    content.Add("client_id", "xxxx");
    content.Add("client_secret", "xxxx");
    content.Add("resource", "https://...");

    UnityWebRequest www = UnityWebRequest.Post("https://login...", content);

    //Send request
    // !! wait until request finishes
    yield return www.SendWebRequest();

    if (!www.isNetworkError && !www.isHttpError)
    {
        string resultContent = www.downloadHandler.text;
        json = JsonUtility.FromJson<TokenClassName>(resultContent);

        //Return result
        token = json.access_token;

        // this should only be done on success
        // execute the callback
        onSuccess?.Invoke(token);
    }
    else
    {
        Debug.LogErrorFormat(this, "Downlaod failed with: {0} - \"{1}\"", www.responseCode, www.error);
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用像回调方法一样使用它

private Start()
{
    StartCoroutine(getAuthToken(OnReceivedToken));
}

privtae void OnReceivedToken(string authToken)
{
    CustomerGroups data = getCustGroups(authToken);

    TextMesh curText = (TextMesh)gameObject.GetComponent(typeof(TextMesh));
    curText.text = data.value[0].Field1+ "-" + data.value[0].Field2;     
}
Run Code Online (Sandbox Code Playgroud)

或作为lambda表达式

private Start()
{
    StartCoroutine(getAuthToken(
        (authToken) =>
        {
            CustomerGroups data = getCustGroups(authToken);

            TextMesh curText = (TextMesh)gameObject.GetComponent(typeof(TextMesh));
            curText.text = data.value[0].Field1+ "-" + data.value[0].Field2;
        }
    ));
}
Run Code Online (Sandbox Code Playgroud)