【问题标题】:Unity C# Nested IEnumeratorUnity C# 嵌套 IEnumerator
【发布时间】:2019-10-17 15:34:14
【问题描述】:

在我的代码中,我嵌套了 IEnumerator 方法,例如:

    private IEnumerator PerformRequest(string url) {

        // Doing stuff

        UnityWebRequest request = UnityWebRequest.Get(url);
        yield return request.SendWebRequest();

        // Doing stuff
    }

    private IEnumerator PerformRequest2(string url) {

        // Doing stuff

        return PerformRequest(url);

        // Doing stuff
    }

    public IEnumerator PerformRequest3(string url) {

        // Doing stuff

        return PerformRequest2(url);

        // Doing stuff
    }

我想知道如果我在上层方法中添加yield 有什么区别,例如:

    private IEnumerator PerformRequest(string url) {

        // Doing stuff

        UnityWebRequest request = UnityWebRequest.Get(url);
        yield return request.SendWebRequest();

        // Doing stuff
    }

    private IEnumerator PerformRequest2(string url) {

        // Doing stuff

        yield return PerformRequest(url);

        // Doing stuff
    }

    public IEnumerator PerformRequest3(string url) {

        // Doing stuff

        yield return PerformRequest2(url);

        // Doing stuff
    }

有区别,还是相同的行为?

谢谢!

【问题讨论】:

  • 我想这会产生一个 IEnumerator>>,这可能不是你想要的。您可以尝试将类型添加到 IEnumerators 以进行检查吗? (无论如何这是个好主意)
  • 是的,这将返回 IEnumerator 的 IEnumerator。除非 Unity 支持它(我不认为它支持),否则它不会工作
  • 事实上,如果我添加yield,它会返回IEnumerator<UnityWebRequestAsyncOperation>IEnumerator<IEnumerator<UnityWebRequestAsyncOperation>>,等等。代码运行没有错误,但我无法真正测试该方法是否真的发送请求(我还没有服务器后端)。但是IEnumerator<T>IEnumerator<IEnumerator<T>> 之间有区别吗?
  • @Adassko 这是 Unity 协程特有的。它的工作方式与常规枚举器类似,但协程也有一些特殊的魔力。
  • @Draco18s 是的,我知道 Unity 中的协程。我不确定如果不测试你是否可以在协程中嵌套协程

标签: c# unity3d


【解决方案1】:

当然,这行得通

我自己之前做过类似的事情,你绝对可以yield 一个它本身产生的方法,因为发生的是执行是完全线性的并且当PerformRequest 产生并返回一些值(网络请求,但实际上并不重要)时,该值传播到PerformRequest2 中的yield return...,然后向上传播到PerformRequest3。 Unity 将在正确的位置恢复执行就好了(你也可以通过测试来回答你自己的问题;)。

基本上它与任何其他嵌套函数相同,例如

int GetValue() {
    return 4;
}

int GetValue2() {
    return GetValue();
}

执行方式完全相同(只是类型不同):

IEnumerator GetValue() {
    return new SomeIEnumerator();
}

IEnumerator GetValue2() {
    return GetValue();
}

转换为协程产生(yield 只是一个特殊的关键字,它不影响返回类型!):

IEnumerator GetValue() {
    yield return new SomeIEnumerator();
}

IEnumerator GetValue2() {
    yield return GetValue();
}

你也可以这样做,但我一般在其中找不到任何价值:

IEnumerator GetValue() {
    yield return new SomeIEnumerator();
}

IEnumerator GetValue2() {
    //other stuff, with yield so our function still returns a value
    StarCoroutine(GetValue());
    //this stuff runs without waiting
}

Adassko 还发现了 this great tutorial 关于协程和嵌套协程的信息。

【讨论】:

  • 最后一个示例StartCoroutine 没有yield 它的工作方式不同,因为上层调用例程GetValue2 不会“停滞”,直到GetValue 完成。为什么有时使用StartCoroutine 可能很好的区别在于,这样你也可以StopCoroutine 它.. 只使用yield return SomeIEnumerator 你不能停止它,除非你停止上面的调用例程我猜......?
  • @derHugo 是的,请参阅这些行上方和下方的 cmets。但是,我看到人们经常将 start coroutine 称为现有协程的 last 行,在这种情况下,它们(实际上)是相同的。
  • 也许 .. 但不是在 OP 的例子中 ;)
【解决方案2】:

在 Draco18 的回答中值得注意的是:

IEnumerator GetValue() {
    // This line won't work.
    yield return new SomeIEnumerator();
}

IEnumerator GetValue2() {
    //other stuff, with yield so our function still returns a value
    StarCoroutine(GetValue());
    //this stuff runs without waiting
}

不起作用,因为您需要在 StartCoroutine 调用中产生嵌套协程, 所以它必须是:

IEnumerator GetValue() {
    // The corrected line.
    yield return StartCoroutine(SomeIEnumerator());
}

IEnumerator GetValue2() {
    //other stuff, with yield so our function still returns a value
    StarCoroutine(GetValue());
    //this stuff runs without waiting
}

【讨论】:

  • 但是..你又没有yieldStartCoroutine(GetValue())..另一个StartCoroutine是多余的,因为你可以简单地直接yield return SomeIEnumerator...
  • @Tenretni 不,因为我假设 StartCoroutine 已经被调用,在 GetValue2(或未显示的 GetValue3)上被调用,SomeIEnumeratorWaitForSeconds 的替代品或类似的(所以这条线肯定有效)。
猜你喜欢
  • 2020-04-25
  • 2017-04-27
  • 2016-08-19
  • 2020-01-01
  • 2020-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-02
相关资源
最近更新 更多