How do you implement the "IDictionaryEnumerator GetEnumerator()" method in IDictionary? - c#

I'm creating a dictionary data structure which implements the IDictionary interface. I'm stuck when it comes to implementing the GetEnumerator method. I have an enumerator which gives KeyValuePair instances but from what I'm finding, I have to implement IDictionaryEnumerator.
Is there a simple way to transform a KeyValuePair enumerator to an IDictionaryEnumerator? I know I can do the following hack:
IDictionaryEnumerator GetEnumerator()
{
return new Dictionary(this.KeyValueEnumerator()).GetEnumerator();
}
But it seems very inefficient as it loads all the enumerator data.

Given that you told us that you have a KeyValueEnumerator() that returns a IEnumerator<KeyValuePair<,>>
// This you told us you have
public IEnumerator<KeyValuePair<TKey, TValue>> KeyValueEnumerator()
{
return something;
}
I built a MyDictionaryEnumerator that exposes a IDictionaryEnumerator interface
// This is what you need
public IDictionaryEnumerator GetEnumerator()
{
return new MyDictionaryEnumerator(KeyValueEnumerator());
}
public class MyDictionaryEnumerator : IDictionaryEnumerator
{
public MyDictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> enumerator)
{
Enumerator = enumerator;
}
public IEnumerator<KeyValuePair<TKey, TValue>> Enumerator;
public DictionaryEntry Entry
{
get { return new DictionaryEntry(Enumerator.Current.Key, Enumerator.Current.Value); }
}
public object Key
{
get { return Enumerator.Current.Key; }
}
public object Value
{
get { return Enumerator.Current.Value; }
}
public object Current
{
get { return Entry; }
}
public bool MoveNext()
{
return Enumerator.MoveNext();
}
public void Reset()
{
Enumerator.Reset();
}
}
The MyDictionaryEnumerator is a very simple class that builds around the KeyValueEnumerator() you have returning DictionaryEntry objects and/or the Key and the Value (I'll say it's an implementation of the Adapter Pattern)

Related

How to use Except operator on non generic ICollection?

I have auto generated by the VS wrapper for WMI collection witch looks like this:
// Enumerator implementation for enumerating instances of the class.
public class DiskDriveCollection : object, ICollection {
private ManagementObjectCollection privColObj;
public DiskDriveCollection(ManagementObjectCollection objCollection) {
privColObj = objCollection;
}
public virtual int Count {
get {
return privColObj.Count;
}
}
public virtual bool IsSynchronized {
get {
return privColObj.IsSynchronized;
}
}
public virtual object SyncRoot {
get {
return this;
}
}
public virtual void CopyTo(System.Array array, int index) {
...
}
public virtual System.Collections.IEnumerator GetEnumerator() {
return new DiskDriveEnumerator(privColObj.GetEnumerator());
}
public class DiskDriveEnumerator : object, System.Collections.IEnumerator {
private ManagementObjectCollection.ManagementObjectEnumerator privObjEnum;
public DiskDriveEnumerator(ManagementObjectCollection.ManagementObjectEnumerator objEnum) {
privObjEnum = objEnum;
}
public virtual object Current {
get {
return new DiskDrive(((System.Management.ManagementObject)(privObjEnum.Current)));
}
}
public virtual bool MoveNext() {
return privObjEnum.MoveNext();
}
public virtual void Reset() {
privObjEnum.Reset();
}
}
}
How can I use except operator with this non generic ICollection?
ICollection inherits from IEnumerable, and there is an OfType method which takes an IEnumerable and returns IEnumerable<T>, then you can easily use all LINQ methods when you got IEnumerable<T>, for example:
myCollection.OfType<object>()
.Except(myOtherCollection.OfType<object>(), new CustomEqualityComparer());
Since you have objects, you need to implement an equality comparer for them an pass it to Except method, otherwise Except will compare your object by references.

implement IEnumerator and IEnumerable in ICollection

I am very new to this ICollection stuff and need some guidance of how to implement the IEnumerable and IEnumerator. I have checked Microsoft documentation and I think I understand what was said there (I think). But when I tried to implement it in my case, I was a bit confused and may need some clarification.
Basically, I declared a class T, then another class Ts which implemented ICollection. In Ts, I have a dictionary.
From the main program, I would like to initialize the class Ts like this:
Ts ts= new Ts(){{a,b}, {c,d}};
so, my questions are:
1) is it legal to do that? It appears that it is as the compiler did not complaint although I have not run the test because I have not thoroughly implement IEnumerable and IEnumerator, which brought to my 2nd question
2) How do I implement IEnumerable and IEnumerator?
Below is my pseudo code to illustrate my points.
public class T
{
string itemName;
int quantity;
.....
public T(string s, int q)
{
.....
}
}
public class Ts: ICollection
{
private Dictionary<string, T> inventory= new Dictionary<string,T>();
public void Add(string s, int q)
{
inventory.Add(s, new T(s,q));
}
public IEnumerator<T> GetEnumerator()
{
// please help
}
IEnumerator IEnumerable.GetEnumerator()
{
// what is the proper GetEnumerator here
}
...
implement other method in ICollection
}
extract from the main program
public Ts CollectionOfT = new Ts(){{"bicycle",100},{"Lawn mower",50}};
.........
The proper implementation is to cast your collection to IEnumerable in the explicit implementation:
IEnumerator IEnumerable.GetEnumerator() {
return ((IEnumerable)your_collection_here).GetEnumerator();
}
For the generic version, call GetEnumerator on your collection:
public IEnumerator<T> GetEnumerator() {
return your_collection_here.GetEnumerator();
}
You must have something that is backing your custom collection.. such as a List, Array, etc. Use that in those implementations.
Honestly you don't need to build your own collection "wrapper" around a Dictionary, but if you must, you can delegate pretty much all the calls to the dictionary for the implementation of the ICollection interface.
Hope this helps
public class Ts: ICollection<T>
{
private Dictionary<string, T> inventory= new Dictionary<string,T>();
//public void Add(string s, int q)
//{
// inventory.Add(s, new T(s,q));
//}
public void Add(T item)
{
inventory.Add(item.ItemName,item);
}
public void Add(string s, int q)
{
inventory.Add(s, new T(s, q));
}
public void Clear()
{
inventory.Clear();
}
public bool Contains(T item)
{
return inventory.ContainsValue(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
inventory.Values.CopyTo(array, arrayIndex);
}
public int Count
{
get { return inventory.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
return inventory.Remove(item.ItemName);
}
public System.Collections.Generic.IEnumerator<T> GetEnumerator()
{
return inventory.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return inventory.Values.GetEnumerator();
}
}
class Program
{
Ts ts = new Ts { { "a", 1 }, { "b", 2 } };
foreach (T t in ts)
{
Console.WriteLine("{0}:{1}",t.ItemName,t.Quantity);
}
}

Windows Phone 7 - OrderedDictionary / alternatives

I'm completely new to C#, so I'm about to make a horrible attempt at my own version of an OrderedDictionary unless someone can suggest an alternative.
I need to be able to access my elements by array index, retaining the order they were added, and I also will be frequently updating individual elements using their key.
Is there a collection that allows this on the phone?
If I keep a List and Dictionary will they both be pointing to the same item or is there some kind of pointer thing I have to do?:
Item i = new Item();
list.Add(i);
dict.Add("key", i);
Here's my implementation (comes from the open source OpenNETCF Extensions library):
public class OrderedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
private Dictionary<TKey, TValue> m_dictionary;
private List<TValue> m_list = new List<TValue>();
private object m_syncRoot = new object();
public OrderedDictionary()
{
m_dictionary = new Dictionary<TKey, TValue>();
}
public OrderedDictionary(IEqualityComparer<TKey> comparer)
{
m_dictionary = new Dictionary<TKey, TValue>(comparer);
}
public void Add(TKey key, TValue value)
{
lock (m_syncRoot)
{
m_dictionary.Add(key, value);
m_list.Add(value);
}
}
public TValue this[int index]
{
get { return m_list[index]; }
}
public TValue this[TKey key]
{
get { return m_dictionary[key]; }
}
public int Count
{
get { return m_dictionary.Count; }
}
public Dictionary<TKey, TValue>.KeyCollection Keys
{
get { return m_dictionary.Keys; }
}
public Dictionary<TKey, TValue>.ValueCollection Values
{
get { return m_dictionary.Values; }
}
public void Clear()
{
lock (m_syncRoot)
{
m_dictionary.Clear();
m_list.Clear();
}
}
public bool ContainsKey(TKey key)
{
return m_dictionary.ContainsKey(key);
}
public bool ContainsValue(TValue value)
{
return m_dictionary.ContainsValue(value);
}
public void Insert(int index, TKey key, TValue value)
{
lock (m_syncRoot)
{
m_list.Insert(index, value);
m_dictionary.Add(key, value);
}
}
public void Remove(TKey key)
{
lock (m_syncRoot)
{
if (ContainsKey(key))
{
var existing = m_dictionary[key];
m_list.Remove(existing);
m_dictionary.Remove(key);
}
}
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return m_dictionary.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Using a List and a Dictionary is probably a good option actually. The "pointer thing" that you're talking about happens by default for Objects in .NET (any class and/or structure). All objects in .NET are passed around by reference.
So, if you use:
Item i = new Item();
list.Add(i);
dict.Add("key",i);
Console.WriteLine(list.Last() == dict["key"]);
Your output will be "true".
Best of luck!
I won't suggest using OrderedDictionary, since it's a non-generic container.
However, if you just want to use it like always. You can port Mono's version of OrderedDictionary.
https://github.com/mono/mono/blob/master/mcs/class/System/System.Collections.Specialized/OrderedDictionary.cs
Here's some tips if you want to port this:
Remove any unavailable interface
Remove serialization-related code
Replace ArrayList with List<object>
Replace Hashtable with Dictionary<object, object>

C# HashSet2 to work exactly like the standard C# HashSet, not compiling

I'm creating my own HashSet that works as the standard HashSet, using a Dictionary. I'm doing this because C# for XNA XBox doesn't support HashSets.
This code is based on code from an example I found. I've edited the example to fix some of the problems but it still won't compile.
public class HashSet2<T> : ICollection<T>
{
private Dictionary<T, Int16> dict;
// code has been edited out of this example
// see further on in the question for the full class
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return dict.GetEnumerator();
}
}
.
'HashSet2<T>' does not implement interface member
'System.Collections.IEnumerable.GetEnumerator()'.
'HashSet2<T>.GetEnumerator()' cannot implement
'System.Collections.IEnumerable.GetEnumerator()'
because it does not have the matching return type of
'System.Collections.IEnumerator'
I'd also be grateful for information on fixing it to be more like the standard HashSet if it deviates in it's behaviour or what it implments in ways that could be unexpected.
Continued from: stackoverflow.com/questions/9966336/c-sharp-xna-xbox-hashset-and-tuple
The most recent vertion of the class:
public class HashSet2<T> : ICollection<T>
{
private Dictionary<T, Int16> dict;
// Dictionary<T, bool>
public HashSet2()
{
dict = new Dictionary<T, short>();
}
public HashSet2(HashSet2<T> from)
{
dict = new Dictionary<T, short>();
foreach (T n in from)
dict.Add(n, 0);
}
public void Add(T item)
{
// The key of the dictionary is used but not the value.
dict.Add(item, 0);
}
public void Clear()
{
dict.Clear();
}
public bool Contains(T item)
{
return dict.ContainsKey(item);
}
public void CopyTo(
T[] array,
int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove(T item)
{
return dict.Remove(item);
}
public System.Collections.IEnumerator GetEnumerator()
{
return ((System.Collections.IEnumerable)
dict.Keys).GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return ((IEnumerable<T>)
dict.Keys).GetEnumerator();
}
public int Count
{
get {return dict.Keys.Count;}
}
public bool IsReadOnly
{
get {return false;}
}
}
You want to enumerate the keys, not the dictionary. Try this:
public IEnumerator GetEnumerator()
{
return ((IEnumerable)dict.Keys).GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return ((IEnumerable<T>)dict.Keys).GetEnumerator();
}
The point is that the HashSet's GetEnumerator returns enumerator that enumerates keys of type T while dictionary's GetEnumerator returns enumerator that enumerates KeyValue object.
UPDATE
Change it to below:
public IEnumerator GetEnumerator()
{
dict.Keys.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return dict.Keys.GetEnumerator();
}
You can simply use Mono's HashSet<T>. You might need to make some minor changes to #if, or remove some interfaces/attributes, but it works on .net.
It's using the MIT X11 license, which is permissive. https://github.com/mono/mono/blob/master/mcs/class/System.Core/System.Collections.Generic/HashSet.cs
Just took a look at the source, and all implementations of GetEnumerator in the Dictionary<TKey, TValue> return the KeyCollection.Enumerator/ValueCollection.Enumerator objects instead of IEnumerator<T> (which is what we need). The good news is that the Key/ValueCollation.Enumerator implement both System.Collection.IEnumerator and IEnumerator<T> interfaces, so you can safely cast to those types.
Try doing this instead:
public IEnumerator GetEnumerator()
{
return (IEnumerator)dict.Keys.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return (IEnumerator<T>)dict.Keys.GetEnumerator();
}

Is there a built-in way to convert IEnumerator to IEnumerable

Is there a built-in way to convert IEnumerator<T> to IEnumerable<T>?
The easiest way of converting I can think of is via the yield statement
public static IEnumerable<T> ToIEnumerable<T>(this IEnumerator<T> enumerator) {
while ( enumerator.MoveNext() ) {
yield return enumerator.Current;
}
}
compared to the list version this has the advantage of not enumerating the entire list before returning an IEnumerable. using the yield statement you'd only iterate over the items you need, whereas using the list version, you'd first iterate over all items in the list and then all the items you need.
for a little more fun you could change it to
public static IEnumerable<K> Select<K,T>(this IEnumerator<T> e,
Func<K,T> selector) {
while ( e.MoveNext() ) {
yield return selector(e.Current);
}
}
you'd then be able to use linq on your enumerator like:
IEnumerator<T> enumerator;
var someList = from item in enumerator
select new classThatTakesTInConstructor(item);
You could use the following which will kinda work.
public class FakeEnumerable<T> : IEnumerable<T> {
private IEnumerator<T> m_enumerator;
public FakeEnumerable(IEnumerator<T> e) {
m_enumerator = e;
}
public IEnumerator<T> GetEnumerator() {
return m_enumerator;
}
// Rest omitted
}
This will get you into trouble though when people expect successive calls to GetEnumerator to return different enumerators vs. the same one. But if it's a one time only use in a very constrained scenario, this could unblock you.
I do suggest though you try and not do this because I think eventually it will come back to haunt you.
A safer option is along the lines Jonathan suggested. You can expend the enumerator and create a List<T> of the remaining items.
public static List<T> SaveRest<T>(this IEnumerator<T> e) {
var list = new List<T>();
while ( e.MoveNext() ) {
list.Add(e.Current);
}
return list;
}
EnumeratorEnumerable<T>
A threadsafe, resettable adaptor from IEnumerator<T> to IEnumerable<T>
I use Enumerator parameters like in C++ forward_iterator concept.
I agree that this can lead to confusion as too many people will indeed assume Enumerators are /like/ Enumerables, but they are not.
However, the confusion is fed by the fact that IEnumerator contains the Reset method. Here is my idea of the most correct implementation. It leverages the implementation of IEnumerator.Reset()
A major difference between an Enumerable and and Enumerator is, that an Enumerable might be able to create several Enumerators simultaneously. This implementation puts a whole lot of work into making sure that this never happens for the EnumeratorEnumerable<T> type. There are two EnumeratorEnumerableModes:
Blocking (meaning that a second caller will simply wait till the first enumeration is completed)
NonBlocking (meaning that a second (concurrent) request for an enumerator simply throws an exception)
Note 1: 74 lines are implementation, 79 lines are testing code :)
Note 2: I didn't refer to any unit testing framework for SO convenience
using System;
using System.Diagnostics;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
namespace EnumeratorTests
{
public enum EnumeratorEnumerableMode
{
NonBlocking,
Blocking,
}
public sealed class EnumeratorEnumerable<T> : IEnumerable<T>
{
#region LockingEnumWrapper
public sealed class LockingEnumWrapper : IEnumerator<T>
{
private static readonly HashSet<IEnumerator<T>> BusyTable = new HashSet<IEnumerator<T>>();
private readonly IEnumerator<T> _wrap;
internal LockingEnumWrapper(IEnumerator<T> wrap, EnumeratorEnumerableMode allowBlocking)
{
_wrap = wrap;
if (allowBlocking == EnumeratorEnumerableMode.Blocking)
Monitor.Enter(_wrap);
else if (!Monitor.TryEnter(_wrap))
throw new InvalidOperationException("Thread conflict accessing busy Enumerator") {Source = "LockingEnumWrapper"};
lock (BusyTable)
{
if (BusyTable.Contains(_wrap))
throw new LockRecursionException("Self lock (deadlock) conflict accessing busy Enumerator") { Source = "LockingEnumWrapper" };
BusyTable.Add(_wrap);
}
// always implicit Reset
_wrap.Reset();
}
#region Implementation of IDisposable and IEnumerator
public void Dispose()
{
lock (BusyTable)
BusyTable.Remove(_wrap);
Monitor.Exit(_wrap);
}
public bool MoveNext() { return _wrap.MoveNext(); }
public void Reset() { _wrap.Reset(); }
public T Current { get { return _wrap.Current; } }
object IEnumerator.Current { get { return Current; } }
#endregion
}
#endregion
private readonly IEnumerator<T> _enumerator;
private readonly EnumeratorEnumerableMode _allowBlocking;
public EnumeratorEnumerable(IEnumerator<T> e, EnumeratorEnumerableMode allowBlocking)
{
_enumerator = e;
_allowBlocking = allowBlocking;
}
private LockRecursionPolicy a;
public IEnumerator<T> GetEnumerator()
{
return new LockingEnumWrapper(_enumerator, _allowBlocking);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class TestClass
{
private static readonly string World = "hello world\n";
public static void Main(string[] args)
{
var master = World.GetEnumerator();
var nonblocking = new EnumeratorEnumerable<char>(master, EnumeratorEnumerableMode.NonBlocking);
var blocking = new EnumeratorEnumerable<char>(master, EnumeratorEnumerableMode.Blocking);
foreach (var c in nonblocking) Console.Write(c); // OK (implicit Reset())
foreach (var c in blocking) Console.Write(c); // OK (implicit Reset())
foreach (var c in nonblocking) Console.Write(c); // OK (implicit Reset())
foreach (var c in blocking) Console.Write(c); // OK (implicit Reset())
try
{
var willRaiseException = from c1 in nonblocking from c2 in nonblocking select new {c1, c2};
Console.WriteLine("Cartesian product: {0}", willRaiseException.Count()); // RAISE
}
catch (Exception e) { Console.WriteLine(e); }
foreach (var c in nonblocking) Console.Write(c); // OK (implicit Reset())
foreach (var c in blocking) Console.Write(c); // OK (implicit Reset())
try
{
var willSelfLock = from c1 in blocking from c2 in blocking select new { c1, c2 };
Console.WriteLine("Cartesian product: {0}", willSelfLock.Count()); // LOCK
}
catch (Exception e) { Console.WriteLine(e); }
// should not externally throw (exceptions on other threads reported to console)
if (ThreadConflictCombinations(blocking, nonblocking))
throw new InvalidOperationException("Should have thrown an exception on background thread");
if (ThreadConflictCombinations(nonblocking, nonblocking))
throw new InvalidOperationException("Should have thrown an exception on background thread");
if (ThreadConflictCombinations(nonblocking, blocking))
Console.WriteLine("Background thread timed out");
if (ThreadConflictCombinations(blocking, blocking))
Console.WriteLine("Background thread timed out");
Debug.Assert(true); // Must be reached
}
private static bool ThreadConflictCombinations(IEnumerable<char> main, IEnumerable<char> other)
{
try
{
using (main.GetEnumerator())
{
var bg = new Thread(o =>
{
try { other.GetEnumerator(); }
catch (Exception e) { Report(e); }
}) { Name = "background" };
bg.Start();
bool timedOut = !bg.Join(1000); // observe the thread waiting a full second for a lock (or throw the exception for nonblocking)
if (timedOut)
bg.Abort();
return timedOut;
}
} catch
{
throw new InvalidProgramException("Cannot be reached");
}
}
static private readonly object ConsoleSynch = new Object();
private static void Report(Exception e)
{
lock (ConsoleSynch)
Console.WriteLine("Thread:{0}\tException:{1}", Thread.CurrentThread.Name, e);
}
}
}
Note 3: I think the implementation of the thread locking (especially around BusyTable) is quite ugly; However, I didn't want to resort to ReaderWriterLock(LockRecursionPolicy.NoRecursion) and didn't want to assume .Net 4.0 for SpinLock
Solution with use of Factory along with fixing cached IEnumerator issue in JaredPar's answer allows to change the way of enumeration.
Consider a simple example: we want custom List<T> wrapper that allow to enumerate in reverse order along with default enumeration. List<T> already implements IEnumerator for default enumeration, we only need to create IEnumerator that enumerates in reverse order. (We won't use List<T>.AsEnumerable().Reverse() because it enumerates the list twice)
public enum EnumerationType {
Default = 0,
Reverse
}
public class CustomList<T> : IEnumerable<T> {
private readonly List<T> list;
public CustomList(IEnumerable<T> list) => this.list = new List<T>(list);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
//Default IEnumerable method will return default enumerator factory
public IEnumerator<T> GetEnumerator()
=> GetEnumerable(EnumerationType.Default).GetEnumerator();
public IEnumerable<T> GetEnumerable(EnumerationType enumerationType)
=> enumerationType switch {
EnumerationType.Default => new DefaultEnumeratorFactory(list),
EnumerationType.Reverse => new ReverseEnumeratorFactory(list)
};
//Simple implementation of reverse list enumerator
private class ReverseEnumerator : IEnumerator<T> {
private readonly List<T> list;
private int index;
internal ReverseEnumerator(List<T> list) {
this.list = list;
index = list.Count-1;
Current = default;
}
public void Dispose() { }
public bool MoveNext() {
if(index >= 0) {
Current = list[index];
index--;
return true;
}
Current = default;
return false;
}
public T Current { get; private set; }
object IEnumerator.Current => Current;
void IEnumerator.Reset() {
index = list.Count - 1;
Current = default;
}
}
private abstract class EnumeratorFactory : IEnumerable<T> {
protected readonly List<T> List;
protected EnumeratorFactory(List<T> list) => List = list;
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public abstract IEnumerator<T> GetEnumerator();
}
private class DefaultEnumeratorFactory : EnumeratorFactory {
public DefaultEnumeratorFactory(List<T> list) : base(list) { }
//Default enumerator is already implemented in List<T>
public override IEnumerator<T> GetEnumerator() => List.GetEnumerator();
}
private class ReverseEnumeratorFactory : EnumeratorFactory {
public ReverseEnumeratorFactory(List<T> list) : base(list) { }
public override IEnumerator<T> GetEnumerator() => new ReverseEnumerator(List);
}
}
As Jason Watts said -- no, not directly.
If you really want to, you could loop through the IEnumerator<T>, putting the items into a List<T>, and return that, but I'm guessing that's not what you're looking to do.
The basic reason you can't go that direction (IEnumerator<T> to a IEnumerable<T>) is that IEnumerable<T> represents a set that can be enumerated, but IEnumerator<T> is a specific enumeratation over a set of items -- you can't turn the specific instance back into the thing that created it.
static class Helper
{
public static List<T> SaveRest<T>(this IEnumerator<T> enumerator)
{
var list = new List<T>();
while (enumerator.MoveNext())
{
list.Add(enumerator.Current);
}
return list;
}
public static ArrayList SaveRest(this IEnumerator enumerator)
{
var list = new ArrayList();
while (enumerator.MoveNext())
{
list.Add(enumerator.Current);
}
return list;
}
}
Nope, IEnumerator<> and IEnumerable<> are different beasts entirely.
This is a variant I have written... The specific is a little different. I wanted to do a MoveNext() on an IEnumerable<T>, check the result, and then roll everything in a new IEnumerator<T> that was "complete" (so that included even the element of the IEnumerable<T> I had already extracted)
// Simple IEnumerable<T> that "uses" an IEnumerator<T> that has
// already received a MoveNext(). "eats" the first MoveNext()
// received, then continues normally. For shortness, both IEnumerable<T>
// and IEnumerator<T> are implemented by the same class. Note that if a
// second call to GetEnumerator() is done, the "real" IEnumerator<T> will
// be returned, not this proxy implementation.
public class EnumerableFromStartedEnumerator<T> : IEnumerable<T>, IEnumerator<T>
{
public readonly IEnumerator<T> Enumerator;
public readonly IEnumerable<T> Enumerable;
// Received by creator. Return value of MoveNext() done by caller
protected bool FirstMoveNextSuccessful { get; set; }
// The Enumerator can be "used" only once, then a new enumerator
// can be requested by Enumerable.GetEnumerator()
// (default = false)
protected bool Used { get; set; }
// The first MoveNext() has been already done (default = false)
protected bool DoneMoveNext { get; set; }
public EnumerableFromStartedEnumerator(IEnumerator<T> enumerator, bool firstMoveNextSuccessful, IEnumerable<T> enumerable)
{
Enumerator = enumerator;
FirstMoveNextSuccessful = firstMoveNextSuccessful;
Enumerable = enumerable;
}
public IEnumerator<T> GetEnumerator()
{
if (Used)
{
return Enumerable.GetEnumerator();
}
Used = true;
return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public T Current
{
get
{
// There are various school of though on what should
// happens if called before the first MoveNext() or
// after a MoveNext() returns false. We follow the
// "return default(TInner)" school of thought for the
// before first MoveNext() and the "whatever the
// Enumerator wants" for the after a MoveNext() returns
// false
if (!DoneMoveNext)
{
return default(T);
}
return Enumerator.Current;
}
}
public void Dispose()
{
Enumerator.Dispose();
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public bool MoveNext()
{
if (!DoneMoveNext)
{
DoneMoveNext = true;
return FirstMoveNextSuccessful;
}
return Enumerator.MoveNext();
}
public void Reset()
{
// This will 99% throw :-) Not our problem.
Enumerator.Reset();
// So it is improbable we will arrive here
DoneMoveNext = true;
}
}
Use:
var enumerable = someCollection<T>;
var enumerator = enumerable.GetEnumerator();
bool res = enumerator.MoveNext();
// do whatever you want with res/enumerator.Current
var enumerable2 = new EnumerableFromStartedEnumerator<T>(enumerator, res, enumerable);
Now, the first GetEnumerator() that will be requested to enumerable2 will be given through the enumerator enumerator. From the second onward the enumerable.GetEnumerator() will be used.
The other answers here are ... strange. IEnumerable<T> has just one method, GetEnumerator(). And an IEnumerable<T> must implement IEnumerable, which also has just one method, GetEnumerator() (the difference being that one is generic on T and the other is not). So it should be clear how to turn an IEnumerator<T> into an IEnumerable<T>:
// using modern expression-body syntax
public class IEnumeratorToIEnumerable<T> : IEnumerable<T>
{
private readonly IEnumerator<T> Enumerator;
public IEnumeratorToIEnumerable(IEnumerator<T> enumerator) =>
Enumerator = enumerator;
public IEnumerator<T> GetEnumerator() => Enumerator;
IEnumerator IEnumerable.GetEnumerator() => Enumerator;
}
foreach (var foo in new IEnumeratorToIEnumerable<Foo>(fooEnumerator))
DoSomethingWith(foo);
// and you can also do:
var fooEnumerable = new IEnumeratorToIEnumerable<Foo>(fooEnumerator);
foreach (var foo in fooEnumerable)
DoSomethingWith(foo);
// Some IEnumerators automatically repeat after MoveNext() returns false,
// in which case this is a no-op, but generally it's required.
fooEnumerator.Reset();
foreach (var foo in fooEnumerable)
DoSomethingElseWith(foo);
However, none of this should be needed because it's unusual to have an IEnumerator<T> that doesn't come with an IEnumerable<T> that returns an instance of it from its GetEnumerator method. If you're writing your own IEnumerator<T>, you should certainly provide the IEnumerable<T>. And really it's the other way around ... an IEnumerator<T> is intended to be a private class that iterates over instances of a public class that implements IEnumerable<T>.

Categories

Resources