I'm not sure what you mean by your question. You posted some code but there are no yields in that code so I don't know what you're trying to ask.
If you're asking about the purpose of the yield keyword in C# then the documentation is pretty good on this topic. I recommend you read up on it. If you're not sure whether you need it or not then you don't need it.
An example may help here.
var orders = GetData();
foreach (var order in orders)
{
ProcessOrder(order);
};
IEnumerable<Order> GetData ()
{
var items = new List<Order>();
items.Add(GetOrder(1));
items.Add(GetOrder(2));
items.Add(GetOrder(3));
return items;
}
Order GetOrder ( int id )
{
Console.WriteLine($"GetOrder({id})");
// Assume this is a DB call that takes a whiel
return new Order() { Id = id };
}
void ProcessOrder ( Order order )
{
// Assume this takes a while
Console.WriteLine($"ProcessORder({order.Id})");
}
public class Order
{
public int Id { get; set; }
}
Run this code. You'll notice that when you call GetData
it gets each order in turn, as shown by the console output. Once all the orders have been retrieved then the call returns and the app can now process the orders one by one.
There are problems with this approach. The first problem is that the caller has to wait for all the data to be retrieved by GetData
before it can start any of its work. This causes the common "stalled UI" issue that you'll see when the UI blocks waiting for a lengthy call to finish. Another issue is that the method has no way of knowing how much of the data you actually care about. Imagine that you don't need all the orders but rather you just want to see if there are any and the GetData
method is the only way to get the data. You'll have to wait for all the data to load just so you can determine if there are any orders, even though you don't plan to do anything with the orders themselves. This is a waste of resources.
yield
allows you to "break out" of a method earlier than normal and return the results you have at that point. In other languages this is referred to as a coroutine. What makes a coroutine different than a regular method is that when the method yields, the state of the method is saved off. When the method is called again, by the same caller, then the method resumes as though it never yielded control. Hence methods that use yield are reentrant and don't need to persist local variables across method calls. The runtime handles this. It is a lot like how threads yield to other threads.
Therefore it is beneficial to use yield
when you are returning IEnumerable<T>
results AND getting each item can be slow. In that case using yield
can increase the performance from the callers point of view because they can get the current item in the results and do whatever with it. Your method won't fetch the next item until the caller asks for it. If they never ask for the next item then you don't waste the resources getting it.
Here's the sample method updated to use yield
instead. The caller doesn't change in any way nor do they even know you're using yield
.
IEnumerable<Order> GetData ()
{
//Return the first item and wait
yield return GetOrder(1);
//Return the second item and wait
yield return GetOrder(2);
//Return the third item and wait
yield return GetOrder(3);
}
Each yield return
pauses the method call and returns the given value as the next item in the IEnumerable<T>
. If the caller asks for another item then the method is called again but it resumes from the previous yield return
. The state of the method is restored automatically by the runtime.
If you run the earlier example using this updated method you'll notice the console writelines are interwoven as GetData
is paused and the caller gets a chance to process the items it gets one by one.
Another benefit of yield
is that it eliminates the need for creating temporary collections to store the results, as done in the original version. This saves memory allocations and tends to simplify the code greatly.
Note that yield
can only be used in methods that return IEnumerable<T>
. This is a language limitation. You cannot use it in any other context.