Can anyone explain IEnumerable and IEnumerator to me?
for example, when to use it over foreach?
You don't use IEnumerable
"over" foreach
. Implementing IEnumerable
makes using foreach
possible.
When you write code like:
foreach (Foo bar in baz)
{
...
}
it's functionally equivalent to writing:
IEnumerator bat = baz.GetEnumerator();
while (bat.MoveNext())
{
bar = (Foo)bat.Current
...
}
By "functionally equivalent," I mean that's actually what the compiler turns the code into. You can't use foreach
on baz
in this example unless baz
implements IEnumerable
.
IEnumerable
means that baz
implements the method
IEnumerator GetEnumerator()
The IEnumerator
object that this method returns must implement the methods
bool MoveNext()
and
Object Current()
The first method advances to the next object in the IEnumerable
object that created the enumerator, returning false
if it's done, and the second returns the current object.
Anything in .Net that you can iterate over implements IEnumerable
. If you're building your own class, and it doesn't already inherit from a class that implements IEnumerable
, you can make your class usable in foreach
statements by implementing IEnumerable
(and by creating an enumerator class that its new GetEnumerator
method will return).
Why do we need IEnumerator and IEnumerable?
I was however able to iterate through a custom collection without the use of either
Of course you can iterate your own collection without the interface; if you couldn't, then how would you implement the interface?
You, as a code implementor, do not implement an interface for your convenience. You implement it for the convenience of the consumer of your code. The interface means "attention customer: you can enumerate the contents of this collection without having to know anything about how I implemented it".
That's the purpose of an interface: it provides an abstraction that allows consumers of your code to use it without having to understand how it works.
What is the difference between IEnumerator and IEnumerable?
IEnumerable is an interface that defines one method GetEnumerator which returns an IEnumerator interface, this in turn allows readonly access to a collection. A collection that implements IEnumerable can be used with a foreach statement.
Definition
IEnumerable
public IEnumerator GetEnumerator();
IEnumerator
public object Current;
public void Reset();
public bool MoveNext();
example code from codebetter.com
What is the reason implementing IEnumerable and IEnumerator
The correct answer is a and this is clear if you take a look at the definitions of the interfaces:
[GuidAttribute("496B0ABE-CDEE-11d3-88E8-00902754C43A")]
[ComVisibleAttribute(true)]
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
And
[ComVisibleAttribute(true)]
[GuidAttribute("496B0ABF-CDEE-11d3-88E8-00902754C43A")]
public interface IEnumerator
{
Object Current { get; }
bool MoveNext();
void Reset();
}
As you notice here, when a type implements the IEnumerable
interface, it should have a method that will return a Enumerator, an object that implements the IEnumerator
interface.
Then the interface called IEnumerator
has one property that holds the current object, when we iterate through a collection and two methods, the MoveNext
and the Reset
. Under the hood, when we iterate through a collection the Iterator's method called MoveNext
is called at first. If this is true we get the first element -- that's the current object. Then method called MoveNext
is get called again and again until it returns false. Each time MoveNext
is called we get an object from the collection, we iterate through.
Why do we have the Reset
method?
As it is stated in MSDN:
Sets the enumerator to its initial position, which is before the first
element in the collection.
IEnumerable and IEnumerator, or foreach C#
If I can do the same with the foreach loop, Why Do I have to use the
interfaces IEnumerable and IEnumerator?
Except for the array, foreach loop utilises the IEnumerable and IEnumerator to display/perform the operations.
But, you cannot exactly modify the element itself using foreach loop, that is only possible on an Enumerator(Iterator in Java). You cannot remove the element using foreach loop.
What is better in performance?
Stick to the foreach loop as you shouldn't reinvent the wheel, unless you have to modify the element from the collection.
Imagine, I am doing a program which spell each letter of a big text,
What Would I have to use? Interfaces or foreach loop?
This is the case where you should simply use foreach loop as you only need to spell each letter of a text, which is a string. You're not modifying the string (not creating a new string) itself.
IEnumerable & IEnumerator
Generally, an IEnumerable
is an object which can be enumerated, such as a list or array. An IEnumerator
is an object that stores the state of the enumeration.
The reason they're not one and the same is that you could have multiple enumerations over the same object at the same time - even in a single-threaded application. For example, consider the following code:
foreach (x in mylist)
{
foreach (y in mylist)
{
if (x.Value == y.Value && x != y)
{
// Found a duplicate value
}
}
}
This would work fine if mylist
is a proper implementation of IEnumerable
, but it would fail if mylist
returned itself as the enumerator.
Understanding IEnumerable - IEnumerator logic
First of all I don't understand how c# knows MyExtensionMethods is an extension of ShoppingCart
it isn't; the "magic" here is the this IEnumerable<Product> products
, which says "the method is an extension method on anything that is IEnumerable<Product>
" - and since ShoppingCart
satisfies that, it works.
then I don't understand how can TotalPrices know that prod come from Products in ShoppingCart class
It doesn't access Products
on ShoppintCart
; it goes via GetEnumerator()
;
this works because foreach (Product prod in products)
can work on (among other things) something that is IEnumerable<Product>
- which we know products
is, because that is how it is defined. This basically then becomes:
public static decimal TotalPrices (this IEnumerable<Product> products)
{
decimal total = 0;
using (var iter = products.GetEnumerator())
{
while (iter.MoveNext())
{
var prod = iter.Current;
total += prod?.Price ?? 0;
}
}
return total;
}
which is all defined via IEnumerable<T>
. The good news is: you usually never need to know this - just know that foreach
works on sequences, and IEnumerable<T>
is a sequence of T
.
Why is IEnumerable T necessary when there is IEnumerator T ?
The two interfaces each represent very different concepts. IEnumerable<T>
is something that "allows enumeration", where IEnumerator<T>
is the representation of the enumeration itself.
If you were to merge these together, it would be impossible to enumerate a single collection more than once at the same time (without some other mechanism in place). For example, two threads doing a foreach
over an array would no longer work, where that is perfectly acceptable in the current design.
Why does interface IEnumerable return IEnumerator GetEnumemrator()? Why not just implement interface IEnumerator?
You can check the differences at this very nice article
TL;DR - Effectively, the IEnumerable
contract assumes that you have a way of maintaning the state of the Enumerable.
Similarities
Both of these interfaces help to loop through the collection.
Relation
The IEnumerable interface actually uses IEnumerator. The main reason to create an IEnumerable is to make the syntax shorter and simpler.
If you go to the definition of the IEnumerable interface, you will see this interface has a method GetEnumerator() that returns an IEnumerator object back.
Differences
The main difference between IEnumerable and IEnumerator is an IEnumerator retains its cursor's current state.
When to use:
So, if you want to loop sequentially through the collection, use an IEnumerable interface else if you want to retain the cursor position and want to pass it from one function to another function then use an IEnumerator interface.
Example:
static void iEnumeratorMethodOne(IEnumerator<string> i)
{
while(i.MoveNext())
{
Console.WriteLine(i.Current);
if(i.Current == "June")
{
iEnumeratorMethodTwo(i);
}
}
}
static void iEnumeratorMethodTwo(IEnumerator<string> i)
{
while(i.MoveNext())
{
Console.WriteLine(i.Current);
}
}
Related Topics
Is Developing in Mono Cross-Platform
Parameters Passed by Reference Come Back Garbage Using P/Invoke
Windows Like Services Development in Linux Using Mono
Reference Assemblies for Framework ".Netframework,Version=V4.7.1" Were Not Found
Generics in C#, Using Type of a Variable as Parameter
System.Missingmethodexception: Method Not Found
.Net Core: Finally Block Not Called on Unhandled Exception on Linux
Routing with Multiple Parameters Using ASP.NET MVC
Saving Any File to in the Database, Just Convert It to a Byte Array
Differencebetween an Int and an Integer in Java and C#
C# VS Java Enum (For Those New to C#)
How to Detect If I'm Running in Mono-Service