2009-08-13 5 views
7

Avec Java Iterator s, j'ai utilisé la méthode hasNext pour déterminer si une itération a plus d'éléments (sans consommer un élément) - ainsi, hasNext est comme une méthode "Peek".Existe-t-il une méthode "HasNext" pour un IEnumerator?

Ma question: y a-t-il quelque chose comme une méthode "hasNext" ou "Peek" avec le IEnumerator générique de C#?

+5

Comment pourriez-vous ne pas savoir? Est-il possible que vous n'avez jamais vu http://msdn.microsoft.com/en-us/library/78dfe2yb.aspx? –

+0

Merci beaucoup d'avoir signalé cela, monsieur Saunders. – JaysonFix

Répondre

15

Non, malheureusement, il n'y en a pas.

L'interface IEnumerator<T> expose que les membres suivants:

Méthodes:

Dispose
MoveNext
Reset

Prope rties:

Current

+1

Merci, Andrew. – JaysonFix

+1

Nous prenons à propos de IEnumerator, au lieu de IEnumerable ici, non? Et * devrait être sur Dispose, au lieu de MoveNext. –

+0

@Even - Yikes, ce poste était plein d'erreurs! Merci de les signaler. –

2

Nope, juste MoveNext, Reset et Current.

33

Non, mais en C# vous pouvez demander à plusieurs reprises l'élément actuel sans passer au suivant. C'est juste une façon différente de voir les choses.

Il ne serait pas trop difficile d'écrire une classe C# pour prendre un style .NET IEnumerator et retourner un style Java Iterator. Personnellement, je trouve le style .NET plus facile à utiliser dans la plupart des cas, mais là nous allons :)

EDIT: D'accord, c'est complètement non testé, mais je pense cela va fonctionner. Il compile au moins :)

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 Ce n'est vraiment qu'une prise différente sur le même modèle. –

+0

(Je suis heureux de coder l'adaptateur si quelqu'un est intéressé, mais je ne le ferai pas autrement ...) –

+3

Je serais intéressé à le voir, Jon. – JaysonFix

3

Les énumérateurs sont souvent évalués paresseux, donc HasNext n'a pas de sens.

Questions connexes