Understanding Iterators, Part 2
Iterators are available for Visual Basic in Visual Studio 2010. In Part 2 of a series, Joe Kunk discusses Visual Basic iterator syntax, demonstrates how iterators are coded, and compares Visual Basic iterators to C# iterators.
As I detailed in Part 1, iterators provide a simple mechanism to asynchronously consume the elements of a collection as they become available, rather than wait for the collection to be fully formed and then processed. Iterators provide a very easy-to-code method to improve application performance via asynchronous processing in the specific case of creating and consuming item collections.
Listing 1 illustrates the use and syntax of a Visual Basic Iterator function. To provide an interesting demo, the free OData Web service of the popular Pluralsight developer training Web site is queried. The application queries the Web service once to determine and display the list of categories when loaded. Clicking on any category in the list initiates a Web service call to determine the list of courses in that category. An iterator is then used to make individual queries to the Web service for each course to obtain the training modules in that course and Yield the course with its modules back to the calling routine as soon as received. An example of the demo screen with the courses and modules for the ASP.NET category is shown in Figure 1.
[Click on image for larger view.]
|Figure 1. Course and Module information obtained via an iterator.|
The fact that an iterator is an asynchronous use of the same thread, and not multi-threaded, can be seen when running the demo application. Click on the larger category like ASP.NET or Visual Studio and start dragging the form around by its title bar before the course-module list completely fills. This ties up the UI thread, the same one used by the iterator. You will notice that the course-module list suspends its fill activity while the screen is being moved and resumes filling as soon as the form is released.
The GetCourseModuleForCategoryIterator function makes a single Web service call to determine the list of courses for the category, then a For Each loop calls the Web service for each course to obtain the list of individual modules. The Yield statement asynchronously returns each course module list to the calling method for display on the applicationform. The code that calls the iterator method is structured as shown here:
'Method initialization code
ForEach item IniL.GetCourseModuleForCategoryIterator(CategoryName)
'Code to display module list to the screen from the returned item object
Listing 2 shows that the GetCourseModuleForCategoryIterator function uses the Iterator modifier in its declaration and returns an IEnumerable(Of T) result. An iterator function must return IEnumerable, IEnumerable(Of T), IEnumerator, or IEnumerator(Of T). Iterators may not have ByRef parameters in order to avoid the possibility of the parameter value changing while the method has Yielded. Iterators cannot occur in events or in constructors.
Listing 2 implements the iterator functionality with a lambda expression to show a second way that iterators can be coded. The CategoryClickLambda method creates a multi-line lambda interator (CourseModulesLambda) inline to return a CourseWithModules instance for each course. Other than the lambda expression, the code is functionally identical to Listing 1.
Finally iterators can be implemented in the Get accessor of a property. Listing 3 demonstrates the same iterator functionality in the CoursesIteratorProperty. It is a read only property with a getter and no setter; the private backing field is not needed since the purpose of the property is to iterate over a set of values and not store information for later retrieval.
The Iterator Type radio button in Figure 1 allows the Course-Module method to be returned using any one of these three iterator syntax choices. I did not notice any difference in performance between the three choices. The Refresh button is useful to see the results repeated without having to select a different category.
Comparison to C# iterators
There are a few differences between Visual Basic and C# iterators beyond the expected syntactical differences.
- Visual Basic allows a Yield statement in the Try block of a Try-Catch-Finally statement; note the Finally block may execute before the For Each iteration completes. Any try block in C# that has a yield return statement may not have a catch block, but may have a Finally block.
- Iterators can be exited in Visual Basic with either Exit Function or Return statements. The yield return statement is required to exit a C# iterator.
- An anonymous function can be an iterator in Visual Basic but not in C#. For both Visual Basic and C#, iterators do not support the IEnumerator.Reset method. To re-iterate from the start, you must obtain a new iterator.
Visual Basic iterators are available in Visual Studio 2010 by installing the Visual Studio Async CTP Version 3, or natively in Visual Studio 11.
Let me Iterate
In this article I have shown three different methods to code an asynchronous iterator in Visual Basic, by function, by lambda expression, and by read only property. The code download has the demonstration application that uses the free Pluralsight OData training Web service to provide a realistic example of the performance benefits of iterator use. Iterators provide a simple way to enhance application responsiveness when creating and consuming collections.
Joe Kunk is a Microsoft MVP in Visual Basic, three-time president of the Greater Lansing User Group for .NET, and developer for Dart Container Corporation of Mason, Michigan. He's been developing software for over 30 years and has worked in the education, government, financial and manufacturing industries. Kunk's co-authored the book "Professional DevExpress ASP.NET Controls" (Wrox Programmer to Programmer, 2009). He can be reached via email at [email protected].