关于c#:统一获取协程的返回值

Getting return value of a Coroutine in unity

本问题已经有最佳答案,请猛点这里访问。

我正在尝试将用户统一插入外部数据库。
我需要等到Web服务器回复错误或成功,但是我无法执行此操作。....

这是我到目前为止所做的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class DBConnector : MonoBehaviour
{
    string BASE_URL ="https://www.XXXXXX.com/API/";

    public DBConnector()
    {
    }

    public int registerUser(User user)
    {
        int returnInt = -1;

        StartCoroutine(RegisterUser(user, returnValue =>
        {
            returnInt = returnValue;
        }
        ));

        Debug.Log(returnInt);
        return returnInt;
    }

    IEnumerator RegisterUser(User user, System.Action<int> callback = null)
    {
        Debug.Log("a register user");

        WWWForm form = new WWWForm();

        using (UnityWebRequest www = UnityWebRequest.Post(BASE_URL +"userAPI.php", form))
        {
            yield return www.SendWebRequest();

            if (www.isNetworkError || www.isHttpError)
            {
                Debug.Log(www.error);
                yield return 1;
            }
            else
            {
                Debug.Log(www.downloadHandler.text);

                yield return 0;
            }
        }
    }
}

并调用它:

1
2
3
4
5
6
7
8
9
10
11
        Debug.Log("Before registerUser");

        conn = FindObjectOfType<DBConnector>();
        result = conn.registerUser(user);

        Debug.Log("After registerUser");

        if (result == 0)
        {
            SceneManager.LoadScene("AccountCreatedScene");
        }

registerUser方法完成后,RegisterUser回调完成,因此始终返回-1。

我在联网方面还是个新手,所以请帮忙.....该怎么做?

谢谢


也有问题:

1
2
3
4
5
6
7
8
9
10
11
12
    int returnInt = -1;

    //This is working async so it won't lock your method, just start your Coroutine and go
    StartCoroutine(RegisterUser(user, returnValue =>
    {
        //Inside callback
        returnInt = returnValue;
    }
    ));

    //go over there where your returnInt is always -1; you should insert that log inside callback
    Debug.Log(returnInt);

长话短说,您应该在lambda

内部实现其余代码

returnValue => {/此处/};

否则它将在协程完成之前被调用

我会这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public void RegisterUser(User user, System.Action<int> callback)
{
    StartCoroutine(RegisterUserCoroutine(user, callback);
}

IEnumerator RegisterUserCoroutine(User user, System.Action<int> callback = null)
{
    Debug.Log("a register user");

    WWWForm form = new WWWForm();

    using (UnityWebRequest www = UnityWebRequest.Post(BASE_URL +"userAPI.php", form))
    {
        yield return www.SendWebRequest();

        if (www.isNetworkError || www.isHttpError)
        {
            //This is also bad, because default value of your callback is null, so it would throw an error
            callback(1);

            //This is better
            callback?.Invoke(1);
        }
        else
        {
            callback(0);
        }
    }
}

您无法使用该int作为返回值,因为您使用的是异步函数。因此,使用该代码代替:

1
2
int userId = RegisterUser( user );
DoSomethingWithUserId( userId );

您应该写:

1
RegisterUser( user, DoSomethingWithUserId );

您实际上需要使用返回值调用callback,这就是为什么您发送的委托没有被调用的原因。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
IEnumerator RegisterUser(User user, System.Action<int> callback = null)
    {
        Debug.Log("a register user");

        WWWForm form = new WWWForm();

        using (UnityWebRequest www = UnityWebRequest.Post(BASE_URL +"userAPI.php", form))
        {
            yield return www.SendWebRequest();

            if (www.isNetworkError || www.isHttpError)
            {
                Debug.Log(www.error);
                if (callback != null) { callback.Invoke(1); }
            }
            else
            {
                Debug.Log(www.downloadHandler.text);

                if (callback != null) { callback.Invoke(0); }
            }
        }
    }

您将需要将场景加载到您发送的委托中;这样,它将在完成后被调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 public void Register(User user)
    {
        StartCoroutine(RegisterUser(user, returnValue =>
        {
            if (returnValue != 0) {
              Debug.LogError("Error");
              return;
            }

            // Place any logic you want post login
            SceneManager.LoadScene("AccountCreatedScene");
        }
        ));
    }

编辑:请注意,这是我在浏览器中编写的伪代码。