【问题标题】:How does this function with a "yield" work in detail?这个带有“产量”的功能如何详细工作?
【发布时间】:2011-03-27 04:53:45
【问题描述】:

我得到了这个方法(在 Unity C# 脚本中),但我不明白“yield”部分的实际工作原理。

我从 MSDN 知道该函数将返回一个 IEnumerator,我可以对其进行迭代,但是这段代码会等待 1.5 秒并且不会进行迭代,因为这意味着在内部创建的对象被创建了多次。 谁能解释一下这段代码是如何工作的?

IEnumerator DestroyShip()
{
    // create new gameobject
    Instantiate(ExplosionPrefab, transform.position, transform.rotation);
    // make current gameobject invisible
    gameObject.renderer.enabled = false;
    // set new position for the current gameobject
    transform.position = new Vector3(0f, transform.position.y, transform.position.z);
    // wait for 1,5 seconds 
    yield return new WaitForSeconds(1.5f);
    // make the current gameobject visible again
    gameObject.renderer.enabled = true;
}

【问题讨论】:

  • 问题标题可能更具描述性。不过,不知何故,谷歌仍然选择了关键字。

标签: c# unity3d yield yield-return


【解决方案1】:

编译器为您生成的枚举器正在被迭代。一次。

编译器将生成一个实现 IEnumerator 的类,该类具有 MoveNext() 函数和 Current 属性。该类将具有存储调用之间函数状态所需的所有成员。确切的细节可以认为是“编译器魔术”。

这个生成类的对象,将由 Unity3d 引擎处理和管理。 Unity3d 引擎将在每个活动的协程上每帧调用一次 MoveNext()(除非另有说明)。

这使 Unity3d 程序员能够编写一次播放一帧的脚本。 C# 编译器魔法和 Unity3d 引擎魔法的组合产生了非常强大但易于使用的脚本。

回答您的问题:您的函数中的代码将执行一次,但会在“yield return”语句处暂停。

如上所述,实现 IEnumerator 的特殊对象由 C# 编译器创建。

在第一次调用 MoveNext() 时,您的函数会创建一个爆炸并将当前对象设置为“new WaitForSeconds(1.5f)”。

Unity3d 引擎检查这个对象,发现它是特殊类“WaitForSeconds”的一个实例,因此将枚举器放在某个等待队列中,并且在 1.5 秒过去之前不会请求第二个元素。同时会渲染很多帧并播放爆炸。

1.5 秒后,Unity 将从队列中抓取枚举数,并再次调用 MoveNext()。您的函数的第二部分现在将执行,但无法生成第二个对象。 MoveNext() 将返回 false 以指示它未能获取新元素,这是给 Unity3d 的信号以丢弃此枚举器。垃圾收集器会在某个时间点回收内存。

如前所述:许多编译器和 Unity3d 魔法正在发生。只要您记得您的函数将在每个 yield return 语句处暂停到下一帧,您就会知道足以从这些特殊函数中受益。

【讨论】:

  • 在独立的 c# 项目中编写该代码,并在 ILSPy 中查看生成的 .net 程序集,让您快速了解所有魔法的工作原理。
【解决方案2】:

如果yield 被使用一次,就好像您返回一个带有一个元素的 IEnumerator,这就是为什么您会觉得它不会迭代。

yield 关键字的用法相当奇怪,如果不看整个上下文就很难理解为什么会这样实现它。

【讨论】:

【解决方案3】:

最好返回IEnumerable 而不是IEnumerator,因为它更灵活且易于使用。最好使用IEnumerable<T>。 Yield return 只是实现迭代器块的语法糖,编译器生成相关代码,因为它本质上是标准样板,可以很容易地以编程方式生成。当你想让一系列单个动作看起来是一个集合时,你通常会使用 yield return,例如:

public IEnumerable<Thing> GetThings()
{
    yield return GetNextThing();
}

【讨论】:

  • 除了 Unity3d 引擎是唯一使用该 IEnumerator 的引擎,并且该引擎要求它是 IEnumerable。可以说 IEnumrable 更好,但也必须配合 Unity3d 的设计理念。
猜你喜欢
  • 1970-01-01
  • 2017-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-29
  • 2020-10-02
  • 1970-01-01
相关资源
最近更新 更多