Foreach On IEnumerable






4.74/5 (12 votes)
Working of foreach loop.
Introduction
I was working with my team on a regular working day. I was using foreach
loop and one of my co-developers asked me if I used
the IEnumerable
collection variable in a foreach
loop constructor. I was aware that foreach
loop can apply
on the IEnumerable
but I was not aware why.
So I searched MSDN for IEnumerable
and I got my answer.
I would like to share this with you.
Background
Let me make a few statements as my background for the concept.
- The
IEnumerable<T>
interface is a generic interface that provides an abstraction for looping over elements. In addition to providingforeach
support, it allows you to use extension methods in theSystem.Linq
namespace. foreach
loop is used on a collection that implements theIEnumerable
interface.foreach
loop returns each element of a collection in the order it is called in the enumeration.foreach
provides in order element access from a collection; it does not accept index and provides access to elements, so eliminates errors caused by incorrect index handling.IEnumerable
is an interface enforcing a rule that we need to implement theGetEnumerator
method.GetEnumerator
method returns anIEnumerator
interface.
Following is the signature for the GetEnumerator
method.
public IEnumerator GetEnumerator(void)
Now we have to implement the IEnumerator
interface with the IEnumerable
interface in order to accept a return value from the GetEnumerator
method.
The IEnumerator
interface enforces rules that we need to implement as follows:
MoveNext
method [public bool MoveNext(void)
]- Increment collection counter by one
- If end of collection has been reached, it will return
false
else returntrue
Reset
method [pubic void Reset(void)
]- Resets the collection index to its initial value of
-1
Current
method [public object Current(void)
]- Return the current index object from collection
Using the Code
- Start Microsoft Visual Studio
- Open File->New->Project->Console Application
- Give some nice name to console application
- Open Project->AddClass
- Give name
Employee
to itpublic class Employee { private int employee_Id; private string employee_Name; public Employee(int employee_Id, string employee_Name) { this.employee_Id = employee_Id; this.employee_Name = employee_Name; } public int Employee_Id { get { return employee_Id; } set { employee_Id=value; } } public string Employee_Name { get { return employee_Name; } set { employee_Name=value; } } }
Employee
class is a single unit type in theforeach
loop.- We have exposed two properties
Employee_Id
andEmployee_Name
. - Now let’s start creating our collection that would be applied on the
Foreach
loop. - Let’s start following statements that we had stated in the background.
- Create class
Employees
and implement theIEnumerable
andIEnumerator
interfaces. - We will also create an
Employee
class array collection and initialize in the constructor by adding anEmployee
object into the collection of theEmployee
array.
public class Employees : IEnumerable,IEnumerator
{
private Employee[] employeeList;
private int position = -1;
public Employees()
{
employeeList = new Employee[4]{
new Employee(1,"Amey"),
new Employee(2,"Pushkar"),
new Employee(3,"Raju"),
new Employee(5,"Vijay")
};
}
public object Current
{
get
{
try
{
return employeeList[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
public bool MoveNext()
{
position++;
return (position < employeeList.Length);
}
public void Reset()
{
position = 0;
}
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
}
Program
class that contains the Main
method. foreach
loop on the Employees
class that implements
the interfaces IEnumerable
and IEnumerator
. The Employees
class contains
an array collection of the Employee
class. Main
method.static void Main(string[] args)
{
var employees = new Employees();
foreach (Employee employee in employees)
{
Console.WriteLine("Employee Id:- "+employee.Employee_Id.ToString()
+"\t\t"
+"Employee Name:- "+employee.Employee_Name);
}
Console.ReadLine();
}
You will observe the following output:
Employee Id: - 1 Employee Name: - Amey
Employee Id: - 2 Employee Name: - Pushkar
Employee Id: - 3 Employee Name: - Raju
Employee Id: - 5 Employee Name: - Vijay
Code optimization
Yield
keyword in C#.Foreach
is not type safe.
In C#, it is not strictly necessary for a collection class to implement IEnumerable
and IEnumerator
in order to be compatible with foreach
.
As long as the class has the required GetEnumerator
, MoveNext
, Reset
, and Current
members, it will work with foreach
.
Or we can say that:
As long as the class has the required GetEnumerator()
function that returns an instance that implements either an IEnumerator
or IEnumerator<T> interface
that enforces to use members MoveNext
, Reset
, and Current.
When you use the yield
keyword in a statement, you indicate that the method, operator, or get accessor in which it appears is an iterator, i.e., Yield
keyword appears in
an iterator block.
When a yield return
statement is reached in the iterator method,
the current state of the code is retain.
An expression that evaluates the value to enumerator [i.e., Employee
class object] is returned and control moves to the caller.
After executing the caller block, control again moves back to the iterator method and restarts from the retain state.
Based on the above statement, we can optimize our Employees
class as below:
public class Employees : IEnumerable
{
private Employee[] employeeList;
private int position = -1;
public Employees()
{
employeeList = new Employee[4]{
new Employee(1,"Amey"),
new Employee(2,"Pushkar"),
new Employee(3,"Raju"),
new Employee(5,"Vijay")
};
}
public IEnumerator GetEnumerator()
{
foreach(Employee employee in employeeList)
yield return employee;
}
}
As our foreach
statement in main
method can be written as:
Foreach(int employee… or Foreach (string employee )
So it is not type safe, right? To make it type safe, let’s declare it as var
which gets assigned its type during runtime.
So our main
function looks like below:
static void Main(string[] args)
{
Employees employees = new Employees();
foreach (var employee in employees)
{
Console.WriteLine("Employee Id:- " +
(employee as Employee).Employee_Id.ToString()
+ "\t\t"
+ "Employee Name:- " +
(employee as Employee).Employee_Name);
}
Console.ReadLine();
}
Notes
- The
foreach
construct comes from C# 1.0, before generics existed. It worked with untyped collections such asArrayList
orIEnumerable
. Therefore, theIEnumerator.Current
property that gets assigned to the loop variable would usually be of typeobject
. - Iterator Pattern falls into the behavioral category. Iterator pattern helps developers to expose
a collection element access in a controlled manner. An iterator allows sequential access of elements without exposing the inside code. It protects
a collection from errors like error caused
by incorrect index handling. When a developer uses a
foreach
loop he is using the Iterator Pattern knowing or unknowingly.
public object Current
{
get
{
try
{
return (Employee)employeeList[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}