IEnumerator or IEnumerator

IEnumerator or IEnumerator<T> :
If you call the GetEnumerator method of IEnumerable or IEnumerable<T> interface, you get an iterator object as an IEnumerator reference.
An IEnumerator has the MoveNext, Current, and Reset methods

IEnumerator.Reset() – Sets the enumerator to its initial position, which is before the first element in the collection.
IEnumerator.Current – Gets the current element in the collection.
IEnumerator.MoveNext() – Move the enumerator to the next element of the collection.

Enumerators can be used to read the data in the collection/list, but they cannot be used to modify the underlying collection.
Each instance of an Enumerator is a a certain position and can give you that element,an enumerator remains valid as long as the collection remains unchanged.If changes are made to the collection, such as add, edit,delete of elements, the enumerator is invalidated and the next call to the MoveNext or Reset method throws an InvalidOperationException.

Example :

class Program1
{
public static IEnumerable<int> GetEvenNumbers(int[] numbers)
{
foreach (int item in numbers)
{
if (item % 2 == 0)
yield return (item);
}
}

public static void Main()
{
// Static collection.
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };

// Return IEnumerable with help of Yield
var evenNumbersCol = GetEvenNumbers(numbers);

// Get IEnumerator from IEnumerable
IEnumerator<int> testNumerator = evenNumbersCol.GetEnumerator();

int sampleNumerator = testNumerator.Current;

Console.WriteLine(“Get first value for Numerator ” + sampleNumerator);

// To advance/get the next value using MoveNext()
if (testNumerator.MoveNext())
{
sampleNumerator = testNumerator.Current;
Console.WriteLine(“Next Even Number = ” + sampleNumerator);
}
// Reset() – Sets the enumerator to its initial position, which is before the first element in the collection.
// testNumerator.Reset();

Console.WriteLine(“After Reset of Numerator ” + testNumerator.Current);

Console.ReadLine();
}
}

Output : –
Get first value for Numerator 0
Next Even Number = 2
After Reset of Numerator 2

As per MSDN
The Reset method is provided for COM interoperability. It does not necessarily need to be implemented; instead, the implementer can simply throw a NotSupportedException.
To verify this please uncomment the 3rd last statement testNumerator.Reset();

Ref – System.Collections.IEnumerator
IEnumerator

Advertisements

The Yield Statement

Yield , one of the most powerfull, most ignored feature by developers.I was one of them until I used it. First ,yield is not an operator. yield return and yield break are statements.

In C#, when we are returning an IEnumerable collection from a method, we are allowed to use the yield keyword to transform method into an “iterator block”.

As per MSDN

The yield keyword signals to the compiler that the method in which it appears is an iterator block.  The compiler generates a class to implement the behavior that is expressed in the iterator block.  In the iterator block, the yield keyword is used together with the return keyword to provide a value to the enumerator object.  This is the value that is returned, for example, in each loop of a foreach statement.  The yield keyword is also used with break to signal the end of iteration.

In other words
The yield keyword is used in an iterator block to provide value of enumerator object or to signal the end of the iteration.

yield keyword can be used as:

1)yield return <expression>;
2)yield break;

When used as the expression is evaluated and returned as a value to the enumerator object.Also the expression has to be implicitebly convertible to yield type of the iterator.

When used as break,Yield break control is unconditionally returned to the caller of the iterator in two cases.
One as specified above is MoveNext method of iterator &  Other can be dispose method of enumerator (iterator) object.

public class Program
{
public static IEnumerable GetEvenNumbers(int[] numbers)
{
foreach (int item in numbers)
{
if (item % 2 == 0)
yield return (item);
}
}
public static IEnumerableGetFirstEvenNumber(int[] numbers)
{
foreach (int item in numbers)
{
if (item % 2 == 0)
{
yield return (item);
yield break;
}
}
//This Loop , will not get called.
foreach (int item in numbers)
{
if (item % 2 == 1)
yield return item;}
}


public static void Main()
{
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };


// Yield Return  – Example Call Start
var evenNumbersCol = GetEvenNumbers(numbers);
foreach (int x in evenNumbersCol)
{
Console.WriteLine(x);
}
// Yield Return  – Example Call End


// Yield Break – Example Call Start
var firstEvenNumber = GetFirstEvenNumber(numbers);
foreach (int x in firstEvenNumber)
{
Console.WriteLine(“First Even Number = ” + x.ToString());
}
// Yield Break – Example Call End
Console.ReadLine();
}

In the Program sample above , I mentioned the example call for both Yield Return & Yield Break

The program will return Even numbers.
The Collection evenNumbersCol/firstEvenNumber is empty before it is been accessed in foreach.The methods are getting called actuallly when any of iterator methods getting called or when looped through in other words when used to return items from a loop within a method ( return type IEnumerable) and retain the state of the method through multiple calls.This saves the memory by preventing fully populating large collection of items

Yield Return:
When used as the expression is evaluated and returned as a value to the enumerator object.”The expression has to be implicitebly convertible to yield type of the iterator.” means return type of yield must match to IEnumerable, in our above case int

Yield Break:
When used as break,Yield break control is unconditionally returned to the caller of the iterator in two cases. One as specified above is Move next method of iterator ( i.e. Looping through as we discussed above) &  Other can be dispose method of enumerator (iterator) object.Also yield break can be seen as return statement which does not return value.
If you are inside this loop want to abort the iteration and return as soon as first even number found , you can do this with help of the yield break. The yield break will return from the method directly instead of the current loop in other words second loop will never get executed here

As per MSDN Yield have following restrictions

The yield statement can only appear inside an iterator block, which can be implemented as the body of a method, operator, or accessor. The body of such methods, operators, or accessors is controlled by the following restrictions:


1) Unsafe blocks are not allowed.
2) Parameters to the method, operator, or accessor cannot be ref or out.
3) A yield return statement cannot be located anywhere inside a try-catch block.
It can be located in a try block if the try block is followed by a finally block.
4) A yield break statement may be located in a try block or a catch block but not a finally block.
5) A yield statement cannot appear in an anonymous method.
6) When used with expression, a yield return statement cannot appear in a catch block or in a try block that has one or more catch clauses.