Yield: Understanding how ‘Yield’ works in the .NET Framework

I first noticed the yield keyword on some shared code at work about a year ago. Befuddled, I read MSDN’s description of the yield keyword a few times, yet I still didn’t completely understand it.

In traffic law, the yield sign is defined as follows:

A yield sign indicates that each driver must prepare to stop if necessary to let a driver on another approach proceed.

This assumes there are multiple cars (a collection) and that one car must wait in order for another to finish clearing the path.

Similar to traffic law, the yield keyword is associated with a collection of objects. When yield returns an object, that object is a single item of the collection and is returned to the caller that will be iterating through the collection.

When To Use Yield

Since the yield return statement is only concerned with one item in a collection, when yield return is used, the collection size is not known at the time. The yielded object is one car in traffic that has no idea about how many total cars will be going through the intersection. It is only concerned with itself.

You should use yield when you need specific logic around an item that will belong to a collection, when you know nothing about the collection as a whole.

For example, let’s say you are developing an API that must handle some wacky business validation when a request comes in. Each property of the request may have its own rules like “this string must be over 10 characters in length” or “another string must start with the letter ‘z'”. When the specific validation triggers for that property, nothing is known about the collection as a whole.

There could be hundreds of similar validations going on at the same time, but that collection of validation exceptions must wait and do something with each specific yielded value.

A Code Example

To continue the scenario from above, here is the output of multiple validation messages using the yield return keywords.

This simple example defines an API endpoint that, when called, triggers the MVC framework’s Validate() method. In the validate method, specific business rules are set up for each property, and then yielded as an error if that business rule is not met. There could be hundreds of these happening when one API call is made, thus each specific error is only concerned with itself and yielded into the collection.

ComplexRequest.cs

public class ComplexRequest : IValidatableObject
{
	[Required]
	public string SomeProperty { get; set; }

	[Required]
	public string SomeProperty2 { get; set; }

	public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
	{
		//custom validation of any properties here

		if (SomeProperty.Length < 10)
		{
			yield return new ValidationResult("SomeProperty: length validation triggered.", new[] { "SomeProperty" });
		}

		if (!SomeProperty2.StartsWith("z"))
		{
			yield return new ValidationResult("SomeProperty: does not start with 'z'.", new[] { "SomeProperty2" });
		}
	}
}

YieldExampleController.cs

[HttpGet]        
public HttpResponseMessage SomeAction([FromUri]ComplexRequest request)
{
	if (!ModelState.IsValid)
	{
		//create a response from any validation triggered
		return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
	}

	//all validation passed
	return new HttpResponseMessage();
}

You can download the solution here. Run it in Visual Studio and navigate to this URL to see it in action:
http://localhost:60261/api/YieldExample/SomeAction?SomeProperty=asdf&SomeProperty2=fdsa

 

Leave a Reply

Your email address will not be published. Required fields are marked *