Page 67 - MSDN Magazine, June 2017
P. 67
Implementing IEnumerable with IEnumerable<T>
System.Collections.Generic.IEnumerable<T> inherits from System.Collections.IEnumerable. Therefore, when implementing IEnumerable<T>, it’s also necessary to implement IEnumerable. In Figure 3, it’s done explicitly, and the implementation simply involves a call to the IEnumerable<T> GetEnumerator implementation. This call from IEnumerable.GetEnumerator to IEnumerable<T>.Get- Enumerator will always work because of the type compatibility (via inheritance) between IEnumerable<T> and IEnumerable. Because the signatures for both GetEnumerators are identical (the return type doesn’t distinguish a signature), one or both implementations must be explicit. Given the additional type safety offered by the IEnumera- ble<T> version, the IEnumerable implementation should be explicit.
The following code uses the Pair<T>.GetEnumerator method and displays “Inigo” and “Montoya” on two consecutive lines:
var fullname = new Pair<string>("Inigo", "Montoya"); foreach (string name in fullname)
{
Console.WriteLine(name); }
Placing a Yield Return Within a Loop
It’s not necessary to hardcode each yield return statement, as I did in both CSharpPrimitiveTypes and Pair<T>. Using the yield return statement, you can return values from inside a loop con- struct. Figure 4 uses a foreach loop. Each time the foreach within GetEnumerator executes, it returns the next value.
Figure 3 Using Yield to Implement BinaryTree<T>
Program
GetEnumerator()
Console
In Figure 4, the first iteration returns the root element within the binary tree. During the second iteration, you traverse the pair of subelements. If the subelement pair contains a non-null value, you traverse into that child node and yield its elements. Note that foreach (T item in tree) is a recursive call to a child node.
As observed with CSharpBuiltInTypes and Pair<T>, you can now iterate over BinaryTree<T> using a foreach loop. Figure 5 demonstrates this process.
And here are the results:
John Fitzgerald Kennedy Joseph Patrick Kennedy Patrick Joseph Kennedy Mary Augusta Hickey
Rose Elizabeth Fitzgerald John Francis Fitzgerald Mary Josephine Hannon
Canceling Further Iteration: Yield Break
Sometimesyoumightwanttocancelfurtheriteration.Youcando so by including an if statement so that no further statements within
primitives: CSharpPrimitiveTypes
MoveNext() yield return “byte”
Instantiate
MoveNext() yield return “object”
The Origin of Iterators
Figure 2 Sequence Diagram with Yield Return msdnmagazine.com
June 2017 63
WriteLine()
enumerator: Enumerator
public struct Pair<T>: IPair<T>, IEnumerable<T>
{
public Pair(T first, T second) : this() {
First = first;
Second = second; }
public T First { get; } // C# 6.0 Getter-only Autoproperty public T Second { get; } // C# 6.0 Getter-only Autoproperty
#region IEnumerable<T>
public IEnumerator<T> GetEnumerator() {
yield return First;
yield return Second; }
#endregion IEnumerable<T>
#region IEnumerable Members System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator() {
return GetEnumerator(); }
#endregion }
In 1972, Barbara Liskov and a team of scientists at MIT began researching programming methodologies, focusing on user-defineddataabstractions.Toprovemuchoftheirwork,they created a language called CLU that had a concept called “clusters” (CLUbeingthefirstthreelettersofthisterm).Clusterswereprede- cessorstotheprimarydataabstractionthatprogrammersusetoday: objects.Duringtheirresearch,theteamrealizedthatalthough theywereabletousetheCLUlanguagetoabstractsomedata representationawayfromendusersoftheirtypes,theyconsistently foundthemselveshavingtorevealtheinnerstructureoftheirdata toallowotherstointelligentlyconsumeit.Theresultoftheir consternation was the creation of a language construct called an iterator.(TheCLUlanguageofferedmanyinsightsintowhatwould eventuallybepopularizedas“object-orientedprogramming.”)
MoveNext() yield return “string”
WriteLine()
WriteLine()