具有“产量”的功能如何正常工作?

时间:2010-08-09 09:14:50

标签: c# unity3d yield yield-return

我有这个方法(在Unity C#Script中),但我不明白“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;
}

3 个答案:

答案 0 :(得分:27)

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

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

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

这使Unity3d Programmer能够编写一次一帧播放的脚本。 C#编译器魔术和Unity3d Engine魔术的结合使得脚本功能非常强大但易于使用。

回答你的问题:你的函数中的代码将被执行一次,但它会在'yield return'语句中暂停。

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

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

Unity3d引擎检查此对象,看到它是特殊类“WaitForSeconds”的实例,因此将枚举器放在某个等待队列上,并且在1.5秒之前不会要求第二个元素。与此同时,将渲染许多帧并播放爆炸。

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

如上所述:许多编译器和Unity3d魔法正在进行中。只要你记得你的函数将被保留到每个yield return语句的下一帧,你就会知道从这些特殊函数中受益。

答案 1 :(得分:5)

如果使用yield一次,就好像你正在返回一个带有一个元素的IEnumerator,这就是为什么你会得到它不会迭代的印象。

使用yield关键字是一个相当奇怪的用法,很难理解为什么它被实现,所以没有看到整个上下文。

答案 2 :(得分:1)

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

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