What Does "Yield Break;" Do in C#

What does yield break; do in C#?

It specifies that an iterator has come to an end. You can think of yield break as a return statement which does not return a value.

For example, if you define a function as an iterator, the body of the function may look like this:

for (int i = 0; i < 5; i++)
{
yield return i;
}

Console.Out.WriteLine("You will see me");

Note that after the loop has completed all its cycles, the last line gets executed and you will see the message in your console app.

Or like this with yield break:

int i = 0;
while (true)
{
if (i < 5)
{
yield return i;
}
else
{
// note that i++ will not be executed after this
yield break;
}
i++;
}

Console.Out.WriteLine("Won't see me");

In this case the last statement is never executed because we left the function early.

Duplicated yield break in Enumerable

Yep, bug. Both reference source and Telerik's JustDecompile simply show

foreach (object obj in source) yield return (TResult)obj;

(JustDecompile adds braces).

Both yield break statements are redundant. And IEnumerator enumerator = null; is a redundant statement as well.

Does Yield Break return a value?

  1. When you Yield Break does the function that contains it return a value to the caller? If so, is it Null/Nothing, the default value for
    the type that the function is, or something else?

No, it does not return a value. It just ends the enumeration. You can say, that it sets IEnumerator.MoveNext() return value to false and that's it.


  1. When you Yield Break does the Iterator start over. In other words, the next time the Iterator is called, will it return the first item in
    the collection again?

It all depends on how your method is written, but when you call the method which uses yield you're creating new instance of state machine, so it can return the same values again.


  1. What is the closest vb.net equivalent to Yield Break? Exit Function? Return Nothing? Something Else?

"You can use an Exit Function or Return statement to end the iteration."

from Yield Statement (Visual Basic)

Is it necessary to call `yield break` after loop?

No this is not necessary. It will work:

public static IEnumerable<int> GetDiff(int start, int end)
{
while (start < end)
{
yield return start;
start++;
}
// yield break; - It is not necessary. It is like `return` which does not return a value.
}

In this case, the execution of the function will end simply by exiting it.

But you can write like this:

public static IEnumerable<int> GetDiff(int start, int end)
{
while (true)
{
if (start >= end)
yield break;
yield return start;
start++;
}
Console.WriteLine("Finish"); // note that this line will not be executed
}

yield return null exits the iteration

Okay the problem is loading scene happens too fast and progress goes to 0.9 right away if you want more control over it you can try this:

    float time = 0;
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("Rotation");
asyncLoad.allowSceneActivation = false;

while (!asyncLoad.isDone)
{
time += Time.deltaTime;
Debug.Log(asyncLoad.progress+" time is"+time);
if (time > 4.0f)
asyncLoad.allowSceneActivation = true;
yield return null;

}

It will load the scene after 4 seconds and if you want this coroutine to keep working after new scene is loaded add DontDestroyOnLoad(this.gameObject) in Start()

I wanted to add this explanation as well after seeing the confusion in the comments. yield return null does not break or return the coroutine. It just returns after your while is executed once and then coroutine continues from where it left in the next frame. The problem in this example is his scene loads in 1 frame so coroutine ends really fast. Normally with yield return null you do 1 iteration in each frame. I hope this helps good luck!

What is the yield keyword used for in C#?

The yield contextual keyword actually does quite a lot here.

The function returns an object that implements the IEnumerable<object> interface. If a calling function starts foreaching over this object, the function is called again until it "yields". This is syntactic sugar introduced in C# 2.0. In earlier versions you had to create your own IEnumerable and IEnumerator objects to do stuff like this.

The easiest way understand code like this is to type-in an example, set some breakpoints and see what happens. Try stepping through this example:

public void Consumer()
{
foreach(int i in Integers())
{
Console.WriteLine(i.ToString());
}
}

public IEnumerable<int> Integers()
{
yield return 1;
yield return 2;
yield return 4;
yield return 8;
yield return 16;
yield return 16777216;
}

When you step through the example, you'll find the first call to Integers() returns 1. The second call returns 2 and the line yield return 1 is not executed again.

Here is a real-life example:

public IEnumerable<T> Read<T>(string sql, Func<IDataReader, T> make, params object[] parms)
{
using (var connection = CreateConnection())
{
using (var command = CreateCommand(CommandType.Text, sql, connection, parms))
{
command.CommandTimeout = dataBaseSettings.ReadCommandTimeout;
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
yield return make(reader);
}
}
}
}
}

Trouble understanding yield in C#

This is called deferred execution, yield is lazy and will only work as much as it needs to.

This has great many advantages, one of which being that you can create seemingly infinite enumerations:

public IEnumerable<int> InfiniteOnes()
{
while (true)
yield 1;
}

Now imagine that the following:

var infiniteOnes = InfiniteOnes();

Would execute eagerly, you'd have a StackOverflow exception coming your way quite happily.

On the other hand, because its lazy, you can do the following:

var infiniteOnes = InfiniteOnes();
//.... some code
foreach (var one in infiniteOnes.Take(100)) { ... }

And later,

foreach (var one in infiniteOnes.Take(10000)) { ... }

Iterator blocks will run only when they need to; when the enumeration is iterated, not before, not after.

Yield continue?

There is no need to have a separate yield continue statement. Just use continue or any other conditional statement to skip the element as you need within your enumeration algorithm.

The enumeration algorithm that uses yield is internally transformed into a state machine by the compiler, which can the be invoked several times. The point of yield is that it generates an output, effectively pausing / stopping the state machine at the place where it's used. The effect of a possible yield continue would be none at all in respect to the behavior of the state machine. Hence it is not needed.

Example:

static IEnumerable<int> YieldTest()
{
for (int value = 1; value <= 4; value++)
{
if (value == 3) continue; // alternatively use if (value != 3) { … }
yield return value;
}
}


Related Topics



Leave a reply



Submit