Why not use yield instead of List<T>.Enumerator - c#

I just find there's a nested struct named Enumerator within the List<> class.
// Returns an enumerator for this list with the given
// permission for removal of elements. If modifications made to the list
// while an enumeration is in progress, the MoveNext and
// GetObject methods of the enumerator will throw an exception.
//
public Enumerator GetEnumerator() {
return new Enumerator(this);
}
[Serializable]
public struct Enumerator : IEnumerator<T>, System.Collections.IEnumerator
{
private List<T> list;
private int index;
private int version;
private T current;
internal Enumerator(List<T> list) {
this.list = list;
index = 0;
version = list._version;
current = default(T);
}
//Omit other code
}
As I know the yield keyword will be translated to above nested struct in IL level, so why Microsoft not use yield directly?

Related

What does a HashSet Enumerator do?

I'm not used to write C# code, only Java and Python.
Now I found some code example for an algorithm which is only available in C#.
There is one structure I don't understand, it is the Enumerator.
HashSet<Node>.Enumerator enumerator = hashSet.GetEnumerator();
enumerator.MoveNext();
Item next = enumerator.Current;
So Item is the data type stored in the HashSet hashSet. Is this equal to a for-loop iterating over a HashSet or how else can that be translated into python or java?
GetEnumerator() methods are presented in some data structures in C# such as List, Set, etc. It enables doing iteration through. Actually, foreach internally makes use of it.
foreach statement is to iterate through the elements of certain data structures. A foreach can be used when all of the following conditions hold:
The data structure implements either IEnumerable(which is to
satisfy legacy codes before generics) or IEnumerable<T> for some
type T.
You do not need to know the locations in the data structure of the
individual elements.
For example, the string class implements both IEnumerable and IEnumerable<Char>.
The IEnumerable<T> interface implies the data structure requires two methods:
public IEnumerator<T> GetEnumerator()
IEnumerator IEnumerable.GetEnumerator()
The latter method is required only because IEnumerable<T> is a subtype of IEnumerable, and that interface requires a GetEnumerator method that returns a non-generic IEnumerator. Both of these methods should return the same object; hence, because IEnumerator<T> is also a subtype of IEnumerator, this method can simply call the first method:
System.Collections.IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
As you can see, the IEnumerable.GetEnumerator() method returns a reference to another interface named System.Collections.IEnumerator. This interface provides the infrastructure to allow the caller to traverse the internal objects contained by the IEnumerable-compatible container:
public interface IEnumerator
{
bool MoveNext (); // Advance the internal position of the cursor.
object Current { get;} // Get the current item (read-only property).
void Reset (); // Reset the cursor before the first member.
}
Let's exemplify it.
public class PowersOfThree : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
return new PowersOfThreeEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
internal class PowersOfThreeEnumerator : IEnumerator<int>
{
private int index = 0;
public int Current
{
get { return (int)System.Math.Pow(3, index); }
}
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public bool MoveNext()
{
index++;
if (index > 10)
return false;
else
return true;
}
public void Reset()
{
index = 0;
}
public void Dispose()
{
}
}
public class Test
{
public static void Main(string[] str)
{
var p2 = new PowersOfThree();
foreach (int p in p2)
{
System.Console.WriteLine(p);
}
}
}
Current method returns the same element until MoveNext method is called. The initial index is 0 each MoveNext method increments the index from 1 to 10, inclusively, then it returns false. When the enumerator is at this position, subsequent calls to MoveNext also return false.
Do you see that what happened to Current when MoveNext returned false? Can you set Current to the first element of the collection again?
If you don't reinstantiate new enumerator, no.

how do I create GetEnumerator of my circular list?

I have to create my own circular list, I using the generic one.
first i create the Node<D> class which represents the data and the next of the element
private class Node<D> {
public D info;
public Node<D> next;
public Node() {
}
public Node(D p) {
info = p;
}
}
To create the circular list, I create the circularList<T> class. this class using Node<> as item of the element.
Here is the CircularList<T> class
class CircularList<T> : IEnumerable<T> {
public Node<T> start;
public Node<T> rear;
public int count = 0;
public CircularList(T firstItem) {
start = new Node<T>(firstItem);
rear = start;
rear.next = start;
}
public void Insert(T newItem) {
//Inserting code here
}
public void Update(T oldItem, T newItem) {
//Updating code is here
}
public void Delete(T theItem) {
//deleting code is here
}
}
when I start to loop using foreach
foreach(string item in CircularList<string>){
}
I got an error says that the circularlist class needs GetEnumerator().
Actually I can loop all of my circular list, but I am using do-while and I need Node<T> to start the loop. but I don't want using Node and do-while.
How do I create the GetEnumerator()?
Any help appreciated. :)
Thank you
Note: I really-really don't understand about IEnumerable and those things, please go easy with the example and explanation.
You need to implement GetEnumerator() method from IEnumerable for the foreach to work.
Use something like following:
public class CircularList<T> : IEnumerable<T>
{
private List<T> mylist = new List<T>();
public T this[int index]
{
get
{
return this.mylist[index];
}
set
{
this.mylist.Insert(index, value);
}
}
public IEnumerator<T> GetEnumerator()
{
return this.mylist.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
mylist maintains the list of type T which you would insert, update and delete.
EDIT
myList is just the backing storage of your "custom" list. As long as you are implementing your underlying functionality correctly, myList could be array, arraylist and so on.
For simplicity, I've used List<T> here which already implements the interface IEnumerable<T> and IEnumerator<T>( notice IEnumera**tor** not IEnumerable).
See this answer for more details on the difference between IEnumerator and IEnumerable
Moreover, The foreach statement hides the complexity of the enumerators.
See IEnumerator for more details.
The compiler turns the foreach into something like this:
CircularList<string> testList=new CircularList<string>();
IEnumerator testEnumerator= testList.GetEnumerator();
while (testEnumerator.MoveNext())
{
string yourForEachIteratorVariable = (string)testEnumerator.Current
...
}
Please note that the codes here are only for the illustration purposes. You could/should modify to make it more flexible and "performant" according to your need/requirement.
And for linked list, you don't need a backing List<T>, you could simply add/insert on your head node and implement GetEnumerator() something like below:
public IEnumerator<T> GetEnumerator()
{
var node = start;
while(node != null)
{
yield return node.info;
node = node.next;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

How can I implement IEnumerator<T>?

This code is not compiling, and it's throwing the following error:
The type 'TestesInterfaces.MyCollection' already contains a definition for 'Current'
But when I delete the ambiguous method, it keeps giving other errors.
Can anyone help?
public class MyCollection<T> : IEnumerator<T>
{
private T[] vector = new T[1000];
private int actualIndex;
public void Add(T elemento)
{
this.vector[vector.Length] = elemento;
}
public bool MoveNext()
{
actualIndex++;
return (vector.Length > actualIndex);
}
public void Reset()
{
actualIndex = -1;
}
void IDisposable.Dispose() { }
public Object Current
{
get
{
return Current;
}
}
public T Current
{
get
{
try
{
T element = vector[actualIndex];
return element;
}
catch (IndexOutOfRangeException e)
{
throw new InvalidOperationException(e.Message);
}
}
}
}
I think you're misunderstanding IEnumerator<T>. Typically, collections implement IEnumerable<T>, not IEnumerator<T>. You can think of them like this:
When a class implements IEnumerable<T>, it is stating "I am a collection of things that can be enumerated."
When a class implements IEnumerator<T>, it is stating "I am a thing that enumerates over something."
It is rare (and probably wrong) for a collection to implement IEnumerator<T>. By doing so, you're limiting your collection to a single enumeration. If you try to loop through the collection within a segment of code that's already looping through the collection, or if you try to loop through the collection on multiple threads simultaneously, you won't be able to do it because your collection is itself storing the state of the enumeration operation. Typically, collections (implementing IEnumerable<T>) return a separate object (implementing IEnumerator<T>) and that separate object is responsible for storing the state of the enumeration operation. Therefore, you can have any number of concurrent or nested enumerations because each enumeration operation is represented by a distinct object.
Also, in order for the foreach statement to work, the object after the in keyword, must implement IEnumerable or IEnumerable<T>. It will not work if the object only implements IEnumerator or IEnumerator<T>.
I believe this is the code you're looking for:
public class MyCollection<T> : IEnumerable<T>
{
private T[] vector = new T[1000];
private int count;
public void Add(T elemento)
{
this.vector[count++] = elemento;
}
public IEnumerator<T> GetEnumerator()
{
return vector.Take(count).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
You need to define the interface the current is implementing.
Object IEnumerator.Current
{
//
}
public T Current
{
//
}
This way your class has 2 Current properties. but you can access them both.
MyCollection<string> col = new MyCollection<string>();
var ienumeratort = col.Current; //Uses IEnumerator<T>
var ienumerator = (IEnumerator)col.Current; //uses IEnumerator
I think with C# 2.0 onwards, you have a very easy way of implementing iterator and compiler does a lot of heavy lifting behind the scene by creating state machine. It's worth looking into it. Having said that, in that case your implementation would look something below:
public class MyCollection<T>
{
private T[] vector = new T[1000];
private int actualIndex;
public void Add(T elemento)
{
this.vector[vector.Length] = elemento;
}
public IEnumerable<T> CreateEnumerable()
{
for (int index = 0; index < vector.Length; index++)
{
yield return vector[(index + actualIndex)];
}
}
}
I am not sure about the purpose of actualIndex though - but i hope you get the idea.
After proper initialization of MyCollection, below is snippet somewhat looks like from consumer perspective:
MyCollection<int> mycoll = new MyCollection<int>();
foreach (var num in mycoll.CreateEnumerable())
{
Console.WriteLine(num);
}

IEnumerator<T> / IEnumerable<T> with position stored only temporarily?

I'm developing a graph where I need to keep the memory usage per node as low as possible. Each node implements IEnumerator / IEnumerable.
IEnumerator / IEnumerable make use of "position" in the canonical examples, which is a persistent cursor value required for iteration (e.g. as used by foreach).
What I need to avoid is storing this "position" value internally to the node itself, as this adds overhead where every byte counts.
How can I construct the node class such that a temporary object stores this value -- preferably on the stack -- only while an iteration is taking place, and not as part of the node itself? Is this possible?
Typically an IEnumerable<T> doesn't store a position - only an IEnumerator<T> does. (Iterator block implementations are odd in terms of implementing both, but they're definitely an anomaly.)
I suggest that you take the same approach that List<T> does: implement IEnumerable<T> with explicit interface implementation, but also have a public method returning a custom mutable struct (horrible I know, but it does solve your problem) which contains a reference to your node and the position within it. When you iterate using foreach, that struct value will only be stored on the stack (normally - assuming you're not doing this within an iterator block, for example).
The normal implementation would be to create a mutable reference type just for the IEnumerator<T>. Normally this is okay as even if you have a lot of IEnumerable<T> values live at the same time, you have few IEnumerator<T> values. Are you concerned about the concurrent number of live objects, or garbage collection?
If "node" is the underlying data, then it is very incorrect to store the position in the node, as you are meant to be able to have separate enumerators. It is unclear how you are currently implementing this API, but if you use an " iterator block " with the position as a local variable it will be done correctly, but on the heap. You can also implement an iterator manually on the stack by creating a struct iterator. It is important that the public GetEnumerator() is returned as the struct type, so you will need to use explicit interface implementation for IEnumerable etc. Note that foreach over Node directly will use the stack, but IEnumerable etc will use the heap.
For example (using a basic linked-list):
using System;
using System.Collections;
using System.Collections.Generic;
class Program
{
static void Main()
{
var list = new MyList<int>();
list.Add(1);
list.Add(2);
list.Add(3);
foreach (var i in list)
{ // this IS NOT using IEnumerable/IEnumerable<T>
Console.WriteLine(i);
}
}
}
public class MyList<T> : IEnumerable<T>
{
internal sealed class Node
{
private readonly T value;
public Node Next { get; set; }
public T Value { get { return value; } }
public Node(T value) { this.value = value; }
}
Node root;
public void Add(T value)
{
var newNode = new Node(value);
var node = root;
if (node == null) root = newNode;
else
{
while (node.Next != null) node = node.Next;
node.Next = newNode;
}
}
public Enumerator GetEnumerator() { return new Enumerator(this); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
IEnumerator<T> IEnumerable<T>.GetEnumerator() { return GetEnumerator(); }
public struct Enumerator : IEnumerator, IEnumerator<T>
{
void IDisposable.Dispose() { node = null; list = null; }
void IEnumerator.Reset() { node = null; }
object IEnumerator.Current { get { return Current; } }
private MyList<T> list;
private Node node;
public bool MoveNext()
{
if (node == null)
{
node = list.root;
return node != null;
}
else
{
if (node.Next == null) return false;
node = node.Next;
return node != null;
}
}
internal Enumerator(MyList<T> list) { this.list = list; node = null; }
public T Current { get { return node == null ? default(T) : node.Value; } }
}
}

How to use foreach keyword on custom Objects in C#

Can someone share a simple example of using the foreach keyword with custom objects?
Given the tags, I assume you mean in .NET - and I'll choose to talk about C#, as that's what I know about.
The foreach statement (usually) uses IEnumerable and IEnumerator or their generic cousins. A statement of the form:
foreach (Foo element in source)
{
// Body
}
where source implements IEnumerable<Foo> is roughly equivalent to:
using (IEnumerator<Foo> iterator = source.GetEnumerator())
{
Foo element;
while (iterator.MoveNext())
{
element = iterator.Current;
// Body
}
}
Note that the IEnumerator<Foo> is disposed at the end, however the statement exits. This is important for iterator blocks.
To implement IEnumerable<T> or IEnumerator<T> yourself, the easiest way is to use an iterator block. Rather than write all the details here, it's probably best to just refer you to chapter 6 of C# in Depth, which is a free download. The whole of chapter 6 is on iterators. I have another couple of articles on my C# in Depth site, too:
Iterators, iterator blocks and data pipelines
Iterator block implementation details
As a quick example though:
public IEnumerable<int> EvenNumbers0To10()
{
for (int i=0; i <= 10; i += 2)
{
yield return i;
}
}
// Later
foreach (int x in EvenNumbers0To10())
{
Console.WriteLine(x); // 0, 2, 4, 6, 8, 10
}
To implement IEnumerable<T> for a type, you can do something like:
public class Foo : IEnumerable<string>
{
public IEnumerator<string> GetEnumerator()
{
yield return "x";
yield return "y";
}
// Explicit interface implementation for nongeneric interface
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator(); // Just return the generic version
}
}
(I assume C# here)
If you have a list of custom objects you can just use the foreach in the same way as you do with any other object:
List<MyObject> myObjects = // something
foreach(MyObject myObject in myObjects)
{
// Do something nifty here
}
If you want to create your own container you can use the yield keyword (from .Net 2.0 and upwards I believe) together with the IEnumerable interface.
class MyContainer : IEnumerable<int>
{
private int max = 0;
public MyContainer(int max)
{
this.max = max;
}
public IEnumerator<int> GetEnumerator()
{
for(int i = 0; i < max; ++i)
yield return i;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
And then use it with foreach:
MyContainer myContainer = new MyContainer(10);
foreach(int i in myContainer)
Console.WriteLine(i);
From MSDN Reference:
The foreach statement is not limited to IEnumerable types and can be applied to an instance of any type that satisfies the following conditions:
has the public parameterless GetEnumerator method whose return type is either class, struct, or interface type,
the return type of the GetEnumerator method has the public Current property and the public parameterless MoveNext method whose return type is Boolean.
If you declare those methods, you can use foreach keyword without IEnumerable overhead. To verify this, take this code snipped and see that it produces no compile-time error:
class Item
{
public Item Current { get; set; }
public bool MoveNext()
{
return false;
}
}
class Foreachable
{
Item[] items;
int index;
public Item GetEnumerator()
{
return items[index];
}
}
Foreachable foreachable = new Foreachable();
foreach (Item item in foreachable)
{
}

Categories