NullReference 错误仅在不在 Unity 3D 播放器中调试时出现
NullReference error only when not debugging in Unity 3D player
我在 Unity 3D 应用程序中工作,其中有 2 种方法可以使用 Oauth 连接到服务:一种方法检索令牌,另一种方法检索服务的 JSON 输出,基于令牌。 JSON 准备就绪后,我将更改 TextMesh 上的文本。 TextMesh 脚本的启动方法中的所有内容 运行ning。像这样:
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;
}
奇怪的是,当我在 Visual Studio 中使用 "Attach to 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)
实际方法是:
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;
}
再一次,如果我不调试它,它会失败,但是当我在 运行 调试它时,它工作得很好。我假设它可能与在 Start 方法中执行它们有关……也许我需要在其他地方执行它?我只需要准备好 JSON 数据,这样我就可以在开始时更改 TextMesh 的值。
您的问题称为 "race condition"。
当你在调试时你是 "slow enough" 所以你的 UnityWebRequest
很可能有一个结果,直到你到达需要它的代码部分。
虽然不调试:您不会等待 直到网络请求完成。
所以当方法到达行
时,www.downloadHandler.text;
仍将具有值 null
json = JsonUtility.FromJson<TokenClassName>(resultContent);
我不知道 exctaly JsonUtility.FromJson
对作为输入值的 null
做了什么,但我猜要么错误已经在那里抛出,要么它可能 return null
所以下一行
token = json.access_token;
尝试使用值 null
访问 json
时抛出异常。
你必须使用 Coroutine and yield
until you have a result (see 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);
}
}
并将其与回调方法一起使用,例如
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;
}
或作为 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;
}
));
}
我在 Unity 3D 应用程序中工作,其中有 2 种方法可以使用 Oauth 连接到服务:一种方法检索令牌,另一种方法检索服务的 JSON 输出,基于令牌。 JSON 准备就绪后,我将更改 TextMesh 上的文本。 TextMesh 脚本的启动方法中的所有内容 运行ning。像这样:
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;
}
奇怪的是,当我在 Visual Studio 中使用 "Attach to 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)
实际方法是:
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;
}
再一次,如果我不调试它,它会失败,但是当我在 运行 调试它时,它工作得很好。我假设它可能与在 Start 方法中执行它们有关……也许我需要在其他地方执行它?我只需要准备好 JSON 数据,这样我就可以在开始时更改 TextMesh 的值。
您的问题称为 "race condition"。
当你在调试时你是 "slow enough" 所以你的 UnityWebRequest
很可能有一个结果,直到你到达需要它的代码部分。
虽然不调试:您不会等待 直到网络请求完成。
所以当方法到达行
时,www.downloadHandler.text;
仍将具有值 null
json = JsonUtility.FromJson<TokenClassName>(resultContent);
我不知道 exctaly JsonUtility.FromJson
对作为输入值的 null
做了什么,但我猜要么错误已经在那里抛出,要么它可能 return null
所以下一行
token = json.access_token;
尝试使用值 null
访问 json
时抛出异常。
你必须使用 Coroutine and yield
until you have a result (see 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);
}
}
并将其与回调方法一起使用,例如
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;
}
或作为 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;
}
));
}