2009-08-13 18 views
7

Con Java Iterator s, ho utilizzato il metodo hasNext per determinare se un'iterazione ha più elementi (senza consumare un elemento) - quindi, hasNext è come un metodo "Peek".Esiste un metodo "HasNext" per un IEnumerator?

La mia domanda: c'è qualcosa come un "hasNext" o il metodo "Peek" con C# s 'generici IEnumerator s?

+5

Come potresti non sapere? È possibile che tu non abbia mai visto http://msdn.microsoft.com/en-us/library/78dfe2yb.aspx? –

+0

Grazie mille per averlo fatto notare, signor Saunders. – JaysonFix

risposta

15

No, purtroppo non c'è.

L'interfaccia IEnumerator<T> espone solo i seguenti membri:

metodi:

Dispose
MoveNext
Reset

Prope proprietā:

Current

+1

Grazie, Andrew. – JaysonFix

+1

Stiamo prendendo in considerazione IEnumerator, invece di IEnumerable qui, giusto? E * dovrebbe essere su Dispose, invece di MoveNext. –

+0

@Even - Yikes, quel post era pieno di errori! Grazie per averli indicati. –

2

Nope, solo MoveNext, Reset e Current.

33

No, ma in C# è possibile chiedere ripetutamente l'elemento corrente senza passare a quello successivo. È solo un modo diverso di guardarlo.

Non sarebbe troppo difficile scrivere una classe C# per prendere un .NET stile IEnumerator e restituire uno stile Java Iterator. Personalmente trovo lo stile .NET facile da usare nella maggior parte dei casi, ma ci andiamo :)

EDIT: Okay, questo è completamente testato, ma io penso che funzionerà. Lo fa almeno compilazione :)

using System; 
using System.Collections; 
using System.Collections.Generic; 

// // Mimics Java's Iterable<T> interface 
public interface IIterable<T> 
{ 
    IIterator<T> Iterator(); 
} 

// Mimics Java's Iterator interface - but 
// implements IDisposable for the sake of 
// parity with IEnumerator. 
public interface IIterator<T> : IDisposable 
{ 
    bool HasNext { get; } 
    T Next(); 
    void Remove(); 
} 

public sealed class EnumerableAdapter<T> : IIterable<T> 
{ 
    private readonly IEnumerable<T> enumerable; 

    public EnumerableAdapter(IEnumerable<T> enumerable) 
    { 
     this.enumerable = enumerable; 
    } 

    public IIterator<T> Iterator() 
    { 
     return new EnumeratorAdapter<T>(enumerable.GetEnumerator()); 
    } 
} 

public sealed class EnumeratorAdapter<T> : IIterator<T> 
{ 
    private readonly IEnumerator<T> enumerator; 

    private bool fetchedNext = false; 
    private bool nextAvailable = false; 
    private T next; 

    public EnumeratorAdapter(IEnumerator<T> enumerator) 
    { 
     this.enumerator = enumerator; 
    } 

    public bool HasNext 
    { 
     get 
     { 
      CheckNext(); 
      return nextAvailable; 
     } 
    } 

    public T Next() 
    { 
     CheckNext(); 
     if (!nextAvailable) 
     { 
      throw new InvalidOperationException(); 
     } 
     fetchedNext = false; // We've consumed this now 
     return next; 
    } 

    void CheckNext() 
    { 
     if (!fetchedNext) 
     { 
      nextAvailable = enumerator.MoveNext(); 
      if (nextAvailable) 
      { 
       next = enumerator.Current; 
      } 
      fetchedNext = true;    
     } 
    } 

    public void Remove() 
    { 
     throw new NotSupportedException(); 
    } 

    public void Dispose() 
    { 
     enumerator.Dispose(); 
    } 
} 

public sealed class IterableAdapter<T> : IEnumerable<T> 
{ 
    private readonly IIterable<T> iterable; 

    public IterableAdapter(IIterable<T> iterable) 
    { 
     this.iterable = iterable; 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     return new IteratorAdapter<T>(iterable.Iterator()); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

public sealed class IteratorAdapter<T> : IEnumerator<T> 
{ 
    private readonly IIterator<T> iterator; 

    private bool gotCurrent = false; 
    private T current; 

    public IteratorAdapter(IIterator<T> iterator) 
    { 
     this.iterator = iterator; 
    } 

    public T Current 
    { 
     get 
     { 
      if (!gotCurrent) 
      { 
       throw new InvalidOperationException(); 
      } 
      return current; 
     } 
    } 

    object IEnumerator.Current 
    { 
     get { return Current; } 
    } 

    public bool MoveNext() 
    { 
     gotCurrent = iterator.HasNext; 
     if (gotCurrent) 
     { 
      current = iterator.Next(); 
     } 
     return gotCurrent; 
    } 

    public void Reset() 
    { 
     throw new NotSupportedException(); 
    } 

    public void Dispose() 
    { 
     iterator.Dispose(); 
    } 
} 
+0

+1 È davvero una presa diversa sullo stesso modello. –

+0

(Sono felice di programmare l'adattatore se qualcuno è interessato, ma non lo farò altrimenti ...) –

+3

Sarei interessato a vederlo, Jon. – JaysonFix

3

Enumerators sono spesso pigramente valutati in modo hasNext ha poco senso.