2008-09-10 7 views
11

Tengo una clase que mapea objetos a objetos, pero a diferencia del diccionario, los mapea en ambos sentidos. Ahora estoy tratando de implementar una interfaz personalizada de IEnumerator que recorre los valores.¿Cómo implementaría la interfaz IEnumerator?

public class Mapper<K,T> : IEnumerable<T>, IEnumerator<T> 

{ 
    C5.TreeDictionary<K,T> KToTMap = new TreeDictionary<K,T>(); 
    C5.HashDictionary<T,K> TToKMap = new HashDictionary<T,K>(); 

    public void Add(K key, T value) 
    { 
     KToTMap.Add(key, value); 
     TToKMap.Add(value, key); 

    } 

    public int Count 
    { 
     get { return KToTMap.Count; } 
    } 


    public K this[T obj] 
    { 
     get 
     { 
      return TToKMap[obj]; 
     } 
    } 

    public T this[K obj] 
    { 
     get 
     { 
      return KToTMap[obj]; 
     } 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     return KToTMap.Values.GetEnumerator(); 
    } 

    public T Current 
    { 
     get { throw new NotImplementedException(); } 
    } 

    public void Dispose() 
    { 
     throw new NotImplementedException(); 
    } 

    object System.Collections.IEnumerator.Current 
    { 
     get { throw new NotImplementedException(); } 
    } 

    public bool MoveNext() 
    { 
     ; 
    } 

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

Respuesta

18

Primero, no haga que su objeto de colección implemente IEnumerator <>. Esto lleva a errores. (Considere la situación en la que dos hilos se repiten en la misma colección).

Implementar un enumerador correctamente resulta ser no trivial, por lo que C# 2.0 agregó soporte de lenguaje especial para hacerlo, basado en la declaración 'yield return'.

La serie reciente de publicaciones de blog de Raymond Chen ("La implementación de iteradores en C# y sus consecuencias") es un buen lugar para ponerse al día.

8

Sólo implementar la interfaz IEnumerable, sin necesidad de aplicar el IEnumerator a menos que desee hacer algunas cosas especiales en el empadronador, lo cual no parece para su caso de ser necesario.

public class Mapper<K,T> : IEnumerable<T> { 
    public IEnumerator<T> GetEnumerator() 
    { 
     return KToTMap.Values.GetEnumerator(); 
    } 
} 

y eso es todo.

+0

Así lo hice al principio, pero más tarde me di cuenta de que me gustaría utilizar para cada uno de estos objetos para obtener los valores. –

+0

para usar foreach en un objeto, el único requisito es que tenga un método publi GetEnumerator() que devuelve e IEnumerator, el objeto ni siquiera tiene que implementar ninguna interfaz, pero se recomienda que implemente IEnumerable o IEnumerable , puedes adivinar por qué;) –

+0

Eso es lo que pensé, así que mi error está en otra parte. Gracias por tranquilizarme –

6

CreateEnumerable() devuelve un IEnumerable que implementa GetEnumerator()

public class EasyEnumerable : IEnumerable<int> { 

    IEnumerable<int> CreateEnumerable() { 
     yield return 123; 
     yield return 456; 
     for (int i = 0; i < 6; i++) { 
      yield return i; 
     }//for 
    }//method 

    public IEnumerator<int> GetEnumerator() { 
     return CreateEnumerable().GetEnumerator(); 
    }//method 

    IEnumerator IEnumerable.GetEnumerator() { 
     return CreateEnumerable().GetEnumerator(); 
    }//method 

}//class 
2

Aquí hay un ejemplo del libro "Algorithms (4th Edition) de Robert Sedgewick".

Estaba escrito en Java y básicamente lo reescribí en C#.

public class Stack<T> : IEnumerable<T> 
{ 
    private T[] array; 

    public Stack(int n) 
    { 
     array = new T[n]; 
    } 

    public Stack() 
    { 
     array = new T[16]; 
    } 

    public void Push(T item) 
    { 
     if (Count == array.Length) 
     { 
      Grow(array.Length * 2); 
     } 

     array[Count++] = item; 
    } 

    public T Pop() 
    { 
     if (Count == array.Length/4) 
     { 
      Shrink(array.Length/2); 
     } 

     return array[--Count]; 
    } 

    private void Grow(int size) 
    { 
     var temp = array; 
     array = new T[size]; 
     Array.Copy(temp, array, temp.Length); 
    } 

    private void Shrink(int size) 
    { 
     Array temp = array; 
     array = new T[size]; 
     Array.Copy(temp,0,array,0,size); 
    } 

    public int Count { get; private set; } 
    public IEnumerator<T> GetEnumerator() 
    { 
     return new ReverseArrayIterator(Count,array); 
    } 

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


    // IEnumerator implementation 
    private class ReverseArrayIterator : IEnumerator<T> 
    { 
     private int i; 

     private readonly T[] array; 

     public ReverseArrayIterator(int count,T[] array) 
     { 
      i = count; 
      this.array = array; 
     } 

     public void Dispose() 
     { 

     } 

     public bool MoveNext() 
     { 
      return i > 0; 
     } 

     public void Reset() 
     { 

     } 

     public T Current { get { return array[--i]; } } 

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