这个函数如何处理“yield”工作?

时间:2021-05-19 08:06:52

I got this method (inside a Unity C# Script), but I do not understand how the "yield" part actually works.

我得到了这个方法(在一个Unity c#脚本中),但是我不理解“yield”部分是如何工作的。

I know from the MSDN that the function will return an IEnumerator which I could iterate throught, but this code waits 1,5 seconds and does not get iterated because this would mean, the objects created inside were created multiple times. Anyone here who can explain me how this code works?

从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 个解决方案

#1


22  

The Enumerator the compiler generates for you is being iterated. Once.

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

The compiler will generate a class that implements IEnumerator, which has a MoveNext() function and a Current property. The class will have all the members required to store the state of the function between calls. The exact details can be considered "Compiler Magic".

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

The object of this generated class, will be handled and managed by the Unity3d Engine. The Unity3d Engine will call MoveNext() on each active coroutine once every frame (unless instructed otherwise).

这个生成的类的对象将由Unity3d引擎处理和管理。Unity3d引擎将会在每帧(除非另有指示)上调用MoveNext()在每个活动的coroutine上。

This enabled the Unity3d Programmer to write scripts that are played out one frame at a time. A combination of C# compiler magic and Unity3d Engine magic results in very-powerful-but-easy-to-use scripting.

这使得Unity3d程序员可以编写一个同时播放一个框架的脚本。c#编译器的魔法和Unity3d引擎魔术的结合,产生了非常容易使用的脚本。

To answer your question: the code in your function will be executed once, but it will pause at the 'yield return' statement.

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

As stated above, a special object that implements IEnumerator is created by the C# compiler.

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

On the first call to MoveNext(), your function creates an explosion and sets the current object to "new WaitForSeconds(1.5f)".

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

The Unity3d engine inspects this object, sees it is an instance of the special class "WaitForSeconds" so puts the enumerator on some waiting queue, and won't ask for the second element until 1.5 sec have passed. In the meantime, many frames will be rendered and the explosion will be played.

Unity3d引擎检查这个对象,看到它是一个特殊类“WaitForSeconds”的实例,所以将枚举器放在一些等待队列中,并且在1.5秒之前不会请求第二个元素。与此同时,许多框架将被渲染,爆炸将被播放。

After 1.5 sec, Unity will grap the enumerator from the queue, and call MoveNext() again. The second part of your function will execute now, but will fail to generate a second object. MoveNext() will return false to indicate it failed to get a new element, which is the signal to Unity3d to throw this enumerator away. The Garbage Collector will reclaim the memory at some point in time.

在1.5秒之后,Unity将把枚举器从队列中删除,并再次调用MoveNext()。函数的第二部分现在将执行,但不会生成第二个对象。MoveNext()将返回false,表示它没有获得一个新元素,这是Unity3d的信号,将这个枚举器抛出。垃圾收集器将在某个时间点回收内存。

As said: lots of compiler and Unity3d magic is going on. As long as you remember that your function will be put on hold till the next frame at each yield return statement, you'll know enough to benefit from those special functions.

正如所说:大量的编译器和Unity3d魔法正在进行。只要你记住,你的函数将被保存到下一帧,在每个yield return语句中,你就会知道这些特殊函数的好处。

#2


5  

If yield is used once, it is as if you were returning an IEnumerator with one element, that's why you get the impression that it does not iterate.

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

It's a rather strange use of the yield keyword, it's difficult to understand why it was implemented so without seeing the whole context.

这是一个非常奇怪的使用yield关键字,很难理解为什么它是这样实现的,没有看到整个上下文。

#3


1  

It is better to return IEnumerable rather than IEnumerator as it is more flaxible and easy to use. It is even better to use IEnumerable<T>. Yield return is just syntactic sugar for implementing an iterator block, the compiler generates the relevent code as it is essentially standard boiler plate that can be easily generated programatically. You generally use yield return when you want to make a series of single actions apear to be a collection, e.g.:

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

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

#1


22  

The Enumerator the compiler generates for you is being iterated. Once.

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

The compiler will generate a class that implements IEnumerator, which has a MoveNext() function and a Current property. The class will have all the members required to store the state of the function between calls. The exact details can be considered "Compiler Magic".

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

The object of this generated class, will be handled and managed by the Unity3d Engine. The Unity3d Engine will call MoveNext() on each active coroutine once every frame (unless instructed otherwise).

这个生成的类的对象将由Unity3d引擎处理和管理。Unity3d引擎将会在每帧(除非另有指示)上调用MoveNext()在每个活动的coroutine上。

This enabled the Unity3d Programmer to write scripts that are played out one frame at a time. A combination of C# compiler magic and Unity3d Engine magic results in very-powerful-but-easy-to-use scripting.

这使得Unity3d程序员可以编写一个同时播放一个框架的脚本。c#编译器的魔法和Unity3d引擎魔术的结合,产生了非常容易使用的脚本。

To answer your question: the code in your function will be executed once, but it will pause at the 'yield return' statement.

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

As stated above, a special object that implements IEnumerator is created by the C# compiler.

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

On the first call to MoveNext(), your function creates an explosion and sets the current object to "new WaitForSeconds(1.5f)".

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

The Unity3d engine inspects this object, sees it is an instance of the special class "WaitForSeconds" so puts the enumerator on some waiting queue, and won't ask for the second element until 1.5 sec have passed. In the meantime, many frames will be rendered and the explosion will be played.

Unity3d引擎检查这个对象,看到它是一个特殊类“WaitForSeconds”的实例,所以将枚举器放在一些等待队列中,并且在1.5秒之前不会请求第二个元素。与此同时,许多框架将被渲染,爆炸将被播放。

After 1.5 sec, Unity will grap the enumerator from the queue, and call MoveNext() again. The second part of your function will execute now, but will fail to generate a second object. MoveNext() will return false to indicate it failed to get a new element, which is the signal to Unity3d to throw this enumerator away. The Garbage Collector will reclaim the memory at some point in time.

在1.5秒之后,Unity将把枚举器从队列中删除,并再次调用MoveNext()。函数的第二部分现在将执行,但不会生成第二个对象。MoveNext()将返回false,表示它没有获得一个新元素,这是Unity3d的信号,将这个枚举器抛出。垃圾收集器将在某个时间点回收内存。

As said: lots of compiler and Unity3d magic is going on. As long as you remember that your function will be put on hold till the next frame at each yield return statement, you'll know enough to benefit from those special functions.

正如所说:大量的编译器和Unity3d魔法正在进行。只要你记住,你的函数将被保存到下一帧,在每个yield return语句中,你就会知道这些特殊函数的好处。

#2


5  

If yield is used once, it is as if you were returning an IEnumerator with one element, that's why you get the impression that it does not iterate.

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

It's a rather strange use of the yield keyword, it's difficult to understand why it was implemented so without seeing the whole context.

这是一个非常奇怪的使用yield关键字,很难理解为什么它是这样实现的,没有看到整个上下文。

#3


1  

It is better to return IEnumerable rather than IEnumerator as it is more flaxible and easy to use. It is even better to use IEnumerable<T>. Yield return is just syntactic sugar for implementing an iterator block, the compiler generates the relevent code as it is essentially standard boiler plate that can be easily generated programatically. You generally use yield return when you want to make a series of single actions apear to be a collection, e.g.:

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

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