2009-08-13 13 views
7

Con Java Iterator s, he usado el método hasNext para determinar si una iteración tiene más elementos (sin consumir un elemento) - por lo tanto, hasNext es como un método "Peek".¿Hay un método "HasNext" para un IEnumerator?

Mi pregunta: ¿hay algo como un método de "Peek" "hasNext" o con C# 's genéricos IEnumerator s?

+5

¿Cómo es posible que no lo sepas? ¿Es posible que nunca hayas visto http://msdn.microsoft.com/en-us/library/78dfe2yb.aspx? –

+0

Muchas gracias por señalar esto, Sr. Saunders. – JaysonFix

Respuesta

15

No, desafortunadamente no lo hay.

La interfaz IEnumerator<T> sólo expone los siguientes miembros:

Métodos:

Dispose
MoveNext
Reset

Prope rtes:

Current

+1

Gracias, Andrew. – JaysonFix

+1

Estamos tomando sobre IEnumerator, en lugar de IEnumerable aquí, ¿verdad? Y * debe estar en Dispose, en lugar de MoveNext. –

+0

@Even - ¡Yikes, esa publicación estaba plagada de errores! Gracias por señalarlos. –

2

Nope, simplemente MoveNext, Reset y Current.

33

No, pero en C# puede pedir repetidamente el elemento actual sin pasar al siguiente. Es solo una forma diferente de verlo.

No sería demasiado difícil escribir una clase C# para tener un estilo de .NET IEnumerator y devolver un estilo de Java Iterator. Personalmente encuentro que el estilo .NET es más fácil de usar en la mayoría de los casos, pero ahí vamos :)

EDITAR: Bien, esto no se ha probado, pero creo que funcionará. Al menos compila :)

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 Realmente es solo una versión diferente del mismo patrón. –

+0

(Me complace codificar el adaptador si alguien está interesado, pero no lo haré de otra manera ...) –

+3

Me interesaría verlo, Jon. – JaysonFix

3

Los enumeradores se evalúan con poca frecuencia para que HasNext tenga poco sentido.

Cuestiones relacionadas