Introduction
This tip explains what actually is an iterator and in how many ways we can implement iterators.
Background
Iterators are available since the early releases of C#. But the use of the Iterators is less known to developers and is also less used. On a daily basis, this concept is less used and also rarely implemented.
Yield behind the scenes produces a state machine for computing the values. This can be seen if you can see the compiled code. Also a point to note is that Yield
keyword which is used in the Iterators offer deferred execution in C# similar to LINQ in C#.
Definition
Quote:
An iterator is a method, get accessor, or operator that performs a custom iteration over an array or collection class by using the yield keyword -- from M S D N
Using Iterator In a Method
Let's have a simple example of returning the products by calling the GetProducts()
method.
public class YieldInMethod
{
public static IEnumerable<string> GetProducts()
{
foreach (var item in Enumerable.Range(1,5))
{
yield return "Product" + item.ToString();
}
}
public static void Main(string[] args)
{
foreach(var item in GetProducts())
{
Console.WriteLine(item);
}
}
}
NOTE: An important point to note while using Iterators is that the return type of the Iterator must be IEnumerable
, IEnumerator
, IEnumerable<t>
, or IEnumerator<t>
.
What Happened?
When yield
return statement is first executed in the Iterator, it immediately returns the product name from the Iterator and writes "Product1
" to the console. When the Iterator
method is called once again, it returns "Product2
" from the Iterator
method and is written to the console and so forth. So, for the second execution, instead of returning "Product1
" from the method, it returned "Product2
" because it knows where it left and resumes the operation, hence returning the second product.
Using Iterator in a GET Accessor
Let's modify the above code a little bit to return the products and Ids from the get
accessor.
public class YieldInGet
{
public IEnumerable<Products> GetProducts
{
get
{
yield return new Products() { Id = 1, Name = "Product1" };
yield return new Products() { Id = 2, Name = "Product2" };
yield return new Products() { Id = 3, Name = "Product3" };
}
}
public static void Main(string[] args)
{
YieldInGet yg = new YieldInGet();
foreach (Products p in yg.GetProducts)
{
Console.WriteLine(String.Format("Product Id: {0}, Name: {1}", p.Id, p.Name));
}
}
}
public class Products
{
public int Id { get; set; }
public string Name { get; set; }
}
When GetProducts
property is accessed for, then the property returns the list of products with ids and names of the products each at a time.
Using Iterator in an Operator
The implementation of yield
in Operator is pretty much the same as the implementation of yield
in a method except that this implementation uses operators to return things.
Let's consider a simple Fibonacci series example to demonstrate using iterator in operator.
public class YieldInOperator
{
public static void Main(string[] args)
{
foreach (var item in Fibonacci(5))
{
Console.WriteLine(item);
}
}
public static IEnumerable<int> Fibonacci(int number)
{
int a = 0, b = 1;
yield return a;
yield return b;
for (int count = 0; count <= number; count++)
{
int temp = a;
a = b;
b = temp + b;
yield return b;
}
}
}
When Fibonnacci(5)
is called, the value of "a
" is returned from the Fibonacci method, followed by b
, followed by the numbers sequence of Fibonacci series.
Summary
Whenever a list of huge values are to be returned, you can use yield
instead of returning a list.