Implementing IEnumerable to my object [duplicate] - c#

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Implementing C# IEnumerable<T> for a LinkedList class
After searching the web for some hours now I still can't understand how IEnumerable/IEnumerator works and how to implement it.
I've constructed a simple LinkedList from scratch but now I want to implement IEnumerable for it so I can foreach it. How do I do that?
class Program
{
LL myList = new LL();
static void Main()
{
var gogo = new Program();
}
public Program()
{
myList.Add("test");
myList.Add("test1");
foreach (var item in myList) //This doesn't work because I havn't implemented Ienumerable
Console.WriteLine(item);
Console.Read();
}
}
class LL
{
private LLNode first;
public void Add(string s)
{
if (this.first == null)
this.first = new LLNode() { Value = s };
else
{
var node = this.first;
while (node.Next != null)
node = node.Next;
node.Next = new LLNode() { Value = s };
}
}
class LLNode
{
public string Value { get; set; }
public LLNode Next { get; set; }
}

It's really not that hard. To implement IEnumerable you just need to implement the GetEnumerator method.
To do that you need to create another class that implements IEnumerator. Implementing IEnumerator is pretty easy. Generally you will pass a reference to your collection when you create the enumerator (in GetEnumerator) and the enumerator will keep track of which item is the current item. Then it will provide MoveNext which just changes the Current to the next item (and returns false if it's at the end of the list) and Reset which just sets the Current back to before the first node.
So in very broad, untested code terms, you need something like:
public class MyLinkedListEnumerator : IEnumerator
{
private LL myList;
private LLNode current;
public object Current
{
get { return current; }
}
public MyLinkedListEnumerator(LL myList)
{
this.myList = myList;
}
public bool MoveNext()
{
if (current == null) {
current = myList.first;
}
else {
current = current.Next;
}
return current != null;
}
public void Reset()
{
current = null;
}
}

What you need to do is:
(1) Make your class implement IEnumerable<T> where T is the type of the enumerated items. (In your case, it looks like it would be LLNode).
(2) Write a public IEnumerator<T> GetEnumerator. Implement it using the "yield" keyword.
(3) Add a IEnumerator IEnumerable.GetEnumerator() method and just return GetEnumerator().
The following code should make this clear. Where I have <int>, you should put <LLNode>, assuming that is the correct type.
using System;
using System.Collections;
using System.Collections.Generic;
namespace Demo
{
internal class Program
{
private static void Main()
{
var test = new MyDemo();
foreach (int item in test)
{
Console.WriteLine(item);
}
}
}
public class MyDemo: IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
// Your implementation of this method will iterate over your nodes
// and use "yield return" to return each one in turn.
for (int i = 10; i <= 20; ++i)
{
yield return i;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
I would have modified your code to do it properly, but the code you posted won't compile.
[EDIT]
Now you've updated your code, I can see that you want to enumerate the values. Here's the completed code:
using System;
using System.Collections;
using System.Collections.Generic;
namespace Demo
{
internal class Program
{
private LL myList = new LL();
private static void Main()
{
var gogo = new Program();
}
public Program()
{
myList.Add("test");
myList.Add("test1");
foreach (var item in myList) // This now works.
Console.WriteLine(item);
Console.Read();
}
}
internal class LL: IEnumerable<string>
{
private LLNode first;
public void Add(string s)
{
if (this.first == null)
this.first = new LLNode
{
Value = s
};
else
{
var node = this.first;
while (node.Next != null)
node = node.Next;
node.Next = new LLNode
{
Value = s
};
}
}
public IEnumerator<string> GetEnumerator()
{
for (var node = first; node != null; node = node.Next)
{
yield return node.Value;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private class LLNode
{
public string Value { get; set; }
public LLNode Next { get; set; }
}
}
}

Related

Short circuit yield return & cleanup/dispose

Take this pseudo example code:
static System.Runtime.InteropServices.ComTypes.IEnumString GetUnmanagedObject() => null;
static IEnumerable<string> ProduceStrings()
{
System.Runtime.InteropServices.ComTypes.IEnumString obj = GetUnmanagedObject();
var result = new string[1];
var pFetched = Marshal.AllocHGlobal(sizeof(int));
while(obj.Next(1, result, pFetched) == 0)
{
yield return result[0];
}
Marshal.ReleaseComObject(obj);
}
static void Consumer()
{
foreach (var item in ProduceStrings())
{
if (item.StartsWith("foo"))
return;
}
}
Question is if i decide to not enumerate all values, how can i inform producer to do cleanup?
Even if you are after a solution using yield return, it might be useful to see how this can be accomplished with an explicit IEnumerator<string> implementation.
IEnumerator<T> derives from IDisposable and the Dispose() method will be called when foreach is left (at least since .NET 1.2, see here)
static IEnumerable<string> ProduceStrings()
{
return new ProduceStringsImpl();
}
This is the class implementing IEnumerable<string>
class ProduceStringsImpl : IEnumerable<string>
{
public IEnumerator<string> GetEnumerator()
{
return new EnumProduceStrings();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
And here we have the core of the solution, the IEnumerator<string> implementation:
class EnumProduceStrings : IEnumerator<string>
{
private System.Runtime.InteropServices.ComTypes.IEnumString _obj;
private string[] _result;
private IntPtr _pFetched;
public EnumProduceStrings()
{
_obj = GetUnmanagedObject();
_result = new string[1];
_pFetched = Marshal.AllocHGlobal(sizeof(int));
}
public bool MoveNext()
{
return _obj.Next(1, _result, _pFetched) == 0;
}
public string Current => _result[0];
void IEnumerator.Reset() => throw new NotImplementedException();
object IEnumerator.Current => Current;
public void Dispose()
{
Marshal.ReleaseComObject(_obj);
Marshal.FreeHGlobal(_pFetched);
}
}
I knew i can! Despite guard, Cancel is called only one time in all circumtances.
You can instead encapsulate logic with a type like IterationResult<T> and provide Cleanup method on it but its essentially same idea.
public class IterationCanceller
{
Action m_OnCancel;
public bool Cancelled { get; private set; }
public IterationCanceller(Action onCancel)
{
m_OnCancel = onCancel;
}
public void Cancel()
{
if (!Cancelled)
{
Cancelled = true;
m_OnCancel();
}
}
}
static IEnumerable<(string Result, IterationCanceller Canceller)> ProduceStrings()
{
var pUnmanaged = Marshal.AllocHGlobal(sizeof(int));
IterationCanceller canceller = new IterationCanceller(() =>
{
Marshal.FreeHGlobal(pUnmanaged);
});
for (int i = 0; i < 2; i++) // also try i < 0, 1
{
yield return (i.ToString(), canceller);
}
canceller.Cancel();
}
static void Consumer()
{
foreach (var (item, canceller) in ProduceStrings())
{
if(item.StartsWith("1")) // also try consuming all values
{
canceller.Cancel();
break;
}
}
}

How to search an element in a Linked List? (c#)

I am given this set of code and I need to fill it up with some code above the while loop and in the While loop. I have seen some documentation but all i have seen is search methods with two arguments and this one only has one. I already wrote the part inside the while loop but im note sure if that is correct. How can I finish this code so that it searches for the value given as the parameter?
note: this is not a homework assignment where I ask you to do it for me, rather this is one of the few resources we have for studying and if you could complete this it would give me a better grasp.
When I run this code now I get this error message:
 Type "Tests.Node" does not contain a definition for "value" and no extension method "value" of type "Tests.Node" could be found. Are you missing an assembly reference?
{
public class Node<T> where T : IComparable
{
public T Value { get; }
public Node<T> Next { get; set; }
public Node(T value, Node<T> next)
{
this.Value = value;
this.Next = next;
}
}
public class LinkedList<T> where T : IComparable
{
public Node<T> start;
public LinkedList()
{
start = null;
}
public LinkedList(Node<T> node)
{
start = node;
}
public Node<T> Search(T value)
{
[here is code needed]
while (start != null)
if(start.value.CompareTo(value) == 0){
return start;
}
start = start.next;
}
}
public class Program {
public static void Main(string[] args){
var list =
new LinkedList<int>(
new Node<int>(
5, new Node<int>(
7, new Node<int>(
21, new Node<int>(
30, null)
)
)
)
);
var a = 21;
var fr = list.Search(a);
}
}
}
You are very close to correct solution. First of all you need to fix compiler errors - change value and next to Value and Next, cause that how properties on your Node class are called.
Next you need to add curly brackets so the while block will execute assignment start = start.Next; (currently only if statement is inside while, so you will end with infinite loop)
Next you need to fix return - add return null; after while block - value you will return if nothing is found (also without it code will not compile).
Lastly you will need to fix the issue with changing the list during search (you are modifying start field of your LinkedList class with start = start.Next, you should not do that), introduce a temporary variable (i've name it curr), assign it value of start and use it in your while loop:
public Node<T> Search(T value)
{
var curr = start;
while (curr != null)
{
if (curr.Value.CompareTo(value) == 0)
{
return curr;
}
curr = curr.Next;
}
return null;
}
I suggest implementing IEnumerable<Node<T>> interface
public class Node<T> : IEnumerable<Node<T>> where T : IComparable {
public IEnumerator<Node<T>> GetEnumerator() {
for (Node<T> item = this; item != null; item = item.Next)
yield return item;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
...
Then you can use Linq to query the collection:
using System.Linq;
...
public static void Main(string[] args) {
LinkedList<int> list = ...
int a = 21;
var fr = list.start.FirstOrDefault(item => item.Value == a);

Implementing C# IEnumerable<T> for a LinkedList class

I'm trying to write a custom LinkedList class in C# using monoDevelop on Linux, just for the sake of testing and learning. The following code never compiles, and I have no idea why!! It doesn't even tell me what's wrong. All what it says is: Error: The compiler appears to have crashed. Check the build output pad for details. When I go to check the output pad, it's not helpful either:
Unhandled Exception: System.ArgumentException: The specified field must be declared on a generic type definition.
Parameter name: field
What can I do?
using System;
using System.Text;
using System.Collections.Generic;
namespace LinkedList
{
public class myLinkedList<T> : IEnumerable<T>
{
//List Node class
//===============
private class ListNode<T>
{
public T data;
public ListNode<T> next;
public ListNode(T d)
{
this.data = d;
this.next = null;
}
public ListNode(T d, ListNode<T> n)
{
this.data = d;
this.next = n;
}
}
//priavte fields
//===============
private ListNode<T> front;
private int size;
//Constructor
//===========
public myLinkedList ()
{
front = null;
size = 0;
}
//public methods
//===============
public bool isEmpty()
{
return (size == 0);
}
public bool addFront(T element)
{
front = new ListNode<T>(element, front);
size++;
return true;
}
public bool addBack(T element)
{
ListNode<T> current = front;
while (current.next != null)
{
current = current.next;
}
current.next = new ListNode<T>(element);
size++;
return true;
}
public override string ToString()
{
ListNode<T> current = front;
if(current == null)
{
return "**** Empty ****";
}
else
{
StringBuilder sb = new StringBuilder();
while (current.next != null)
{
sb.Append(current.data + ", ");
current = current.next;
}
sb.Append(current.data);
return sb.ToString();
}
}
// These make myLinkedList<T> implement IEnumerable<T> allowing
// a LinkedList to be used in a foreach statement.
public IEnumerator<T> GetEnumerator()
{
return new myLinkedListIterator<T>(front);
}
private class myLinkedListIterator<T> : IEnumerator<T>
{
private ListNode<T> current;
public virtual T Current
{
get
{
return current.data;
}
}
private ListNode<T> front;
public myLinkedListIterator(ListNode<T> f)
{
front = f;
current = front;
}
public bool MoveNext()
{
if(current.next != null)
{
current = current.next;
return true;
}
else
{
return false;
}
}
public void Reset()
{
current = front;
}
public void Dispose()
{
throw new Exception("Unsupported Operation");
}
}
}
}
You need to add the non-generic APIs; so add to the iterator:
object System.Collections.IEnumerator.Current { get { return Current; } }
and to the enumerable:
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
HOWEVER! If you are implementing this by hand, you are missing a trick. An "iterator block" would be much easier.
The following is a complete implementation; you don't need to write an enumerator class at all (you can remove myLinkedListIterator<T> completely):
public IEnumerator<T> GetEnumerator()
{
var node = front;
while(node != null)
{
yield return node.data;
node = node.next;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
When i tried the code that you have pasted i get 2 errors when trying to build.
myLinkedList' does not implement interface member
'System.Collections.IEnumerable.GetEnumerator()'.
'.myLinkedList.GetEnumerator()' cannot implement
'System.Collections.IEnumerable.GetEnumerator()' because it does not
have the matching return type of 'System.Collections.IEnumerator'.
Solution is to implement the following in the first class.
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
And the second error is :
myLinkedList.myLinkedListIterator' does not implement interface
member 'System.Collections.IEnumerator.Current'.
'JonasApplication.myLinkedList.myLinkedListIterator.Current'
cannot implement 'System.Collections.IEnumerator.Current' because it
does not have the matching return type of 'object'.
Solution to the second could be something as following to implement in the second class.
object IEnumerator.Current
{
get { return Current; }
}

call graph IEnumerator

I have to implement a call graph for expressions like Id = Id(Param); and that wasn't a problem.
Now I have to implement an enumerator which lists one at a time all topological orderings among the calls that satisfy the order of dependencies.
And here's the trouble.
This is a simple node for the call graph:
class CallGraphNode
{
private string name;
public List<CallGraphNode> dependents = new List<CallGraphNode>();
public int dependencies;
private bool executed = false;
public bool Executable { get { return dependencies == 0; } }
public bool Executed { get { return executed; } set { executed = value; } }
public CallGraphNode(string name)
{
this.name = name;
dependencies = 0;
}
public override string ToString()
{
return name;
}
public void AddDependent(CallGraphNode n)
{
dependents.Add(n);
}
}
And this is the call graph class itself:
class CallGraph : IEnumerable<List<CallGraphNode>>
{
public List<CallGraphNode> nodes = new List<CallGraphNode>();
public void AddNode(CallGraphNode n)
{
nodes.Add(n);
}
public static void Show(IEnumerable<CallGraphNode> n)
{
foreach (CallGraphNode node in n)
{
Console.Write("{0} ", node);
}
Console.WriteLine();
}
static IEnumerable<List<CallGraphNode>> EnumerateFunctions(List<CallGraphNode> executable, List<CallGraphNode> res)
{
if (executable.Count == 0)
yield return res;
else foreach (CallGraphNode n in executable)
{
if (!n.Executed)
res.Add(n);
List<CallGraphNode> next_executable = new List<CallGraphNode>(executable);
executable.Remove(n);
foreach (CallGraphNode m in n.dependents)
if (--m.dependencies == 0)
next_executable.Add(m);
foreach (List<CallGraphNode> others in EnumerateFunctions(next_executable, res))
yield return others;
foreach (CallGraphNode m in n.dependents)
m.dependencies++;
if (!n.Executed)
res.Remove(n);
}
}
IEnumerator<List<CallGraphNode>> IEnumerable<List<CallGraphNode>>.GetEnumerator()
{
List<CallGraphNode> executable = new List<CallGraphNode>();
foreach (CallGraphNode n in nodes)
if (n.Executable || n.Executed)
executable.Add(n);
List<CallGraphNode> output = new List<CallGraphNode>();
foreach (List<CallGraphNode> list in EnumerateFunctions(executable, output))
yield return list;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{ throw new NotImplementedException(); }
}
Now, the problem is it just won't work. When I try to create an IEnumerator and assign it the GetEnumerator() return value, I get a casting error and that's honestly what I expected when trying to do so:
IEnumerator<List<CallGraphNode>> lt = cg.GetEnumerator();
Then I've tried:
System.Collections.Generic.List<CallGraphNode>.Enumerator en = cg.nodes.GetEnumerator();
This works, but the method EnumerateFunctions is never called and the enumerator just contains the original list of graph nodes.
Any ideas?
The problem is that you're implementing both IEnumerable<T> and IEnumerable using explicit interface implementation.
You probably want to change this declaration:
IEnumerator<List<CallGraphNode>> IEnumerable<List<CallGraphNode>>.GetEnumerator()
to be a "normal" interface implementation:
public IEnumerator<List<CallGraphNode>> GetEnumerator()
Alternatively, you could stick with explicit interface implementation, but use:
IEnumerable<List<CallGraphNode>> sequence = cg;
IEnumerator<List<CallGraphNode>> lt = sequence.GetEnumerator();

C#: Circular enumeration of IEnumerable<T>

There is the command hierarchy in my current application.
public interface ICommand
{
void Execute();
}
So, some commands are stateful, some are not.
I need to enumerate IEnumerable in the circular way for some command implementation during command execution.
public class GetNumberCommand : ICommand
{
public GetNumberCommand()
{
List<int> numbers = new List<int>
{
1, 2, 3
};
}
public void Execute()
{
// Circular iteration here.
// 1 => 2 => 3 => 1 => 2 => 3 => ...
}
public void Stop()
{
// Log current value. (2 for example)
}
}
Execute is called from time to time, so it is necessary to store the iteration state.
How to implement that circular enumeration?
I have found two solutions:
Using the IEnumerator<T> interface.
It looks like:
if (!_enumerator.MoveNext())
{
_enumerator.Reset();
_enumerator.MoveNext();
}
Using the circular IEnumerable<T> (yield forever the same sequence): “Implementing A Circular Iterator” - HonestIllusion.Com.
Maybe, there are more ways to achieve it.
What would you recommend to use and why?
Instead of dealing with IEnumerator interface,
foreach (var x in GetSomething())
{
if (someCondition) break;
}
public IEnumerable<int> GetSomething()
{
List<int> list = new List<int>() { 1, 2, 3 };
int index=0;
while (true)
yield return list[index++ % list.Count];
}
Here's one I just implemented as an extension.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace DroopyExtensions
{
public static class CircularEnumaratorExtensionMethod
{
public static IEnumerator<T> GetCircularEnumerator<T>(this IEnumerable<T> t)
{
return new CircularEnumarator<T>(t.GetEnumerator());
}
private class CircularEnumarator<T> : IEnumerator<T>
{
private readonly IEnumerator _wrapedEnumerator;
public CircularEnumarator(IEnumerator wrapedEnumerator)
{
this._wrapedEnumerator = wrapedEnumerator;
}
public object Current => _wrapedEnumerator.Current;
T IEnumerator<T>.Current => (T)Current;
public void Dispose()
{
}
public bool MoveNext()
{
if (!_wrapedEnumerator.MoveNext())
{
_wrapedEnumerator.Reset();
return _wrapedEnumerator.MoveNext();
}
return true;
}
public void Reset()
{
_wrapedEnumerator.Reset();
}
}
}
}
To use it, all you have to do is
using DroopyExtensions;
class Program
{
static void Main(string[] args)
{
var data = new List<string>() {"One", "Two", "Tree"};
var dataEnumerator = data.GetCircularEnumerator();
while(dataEnumerator.MoveNext())
{
Console.WriteLine(dataEnumerator.Current);
}
}
}
You can use this extension method:
public static IEnumerable<T> Cyclic<T>(this IEnumerable<T> #this)
{
while (true)
foreach (var x in #this)
yield return x;
}
In that way:
public class GetNumberCommand : ICommand
{
private readonly IEnumerator<int> _commandState = new[] { 1, 2, 3 }.Cyclic().GetEnumerator();
public void Execute()
{
_commandState.MoveNext();
var state = _commandState.Current;
//
// Do stuff with state
//
}
public void Stop()
{
var state = _commandState.Current;
// Log state value. (2 for example)
}
}
while (!stop)
{
foreach (var i in numbers)
{
// do something
}
}
I think, the most comfortable way wil be to implement custom collection with custom enumerator and encapsulate circular logic in it.
class Collection<T> : IEnumerable<T>
{
bool circle;
List<T> collection = new List<T>();
public IEnumerable<T> IEnumerable<T>.GetEnumerator()
{
if(circle) return new CustomEnumerator<T>(this);
return circle.GetEnumerator();
}
}
class CustomEnumerator : Enumerator<T> {}
something like this...
You can write a circular enumerable without yield returns.
public class CircularEnumerable<T> : IEnumerable<T>
{
public CircularEnumerable (IEnumerable<T> sequence)
{
InfiniteLoop = sequence.Concat (this);
}
private readonly IEnumerable<T> InfiniteLoop;
public IEnumerator<T> GetEnumerator ()
{
return InfiniteLoop.GetEnumerator ();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
{
return InfiniteLoop.GetEnumerator ();
}
}
public class GetNumberCommand : ICommand
{
public GetNumberCommand()
{
List<int> numbers = new List<int>
{
1, 2, 3
};
infiniteLoopOnNumbers = new CircularEnumerable<int>(numbers).GetEnumerator();
}
IEnumerator<int> infiniteLoopOnNumbers;
public void Execute()
{
infiniteLoopOnNumbers.MoveNext();
}
public void Stop()
{
int value = infiniteLoopOnNumbers.Current;
}
}

Categories